Java 核心概念
Java 核心概念:从一次编译到处运行开始
📖 本文是 Java 基础知识系列的第一篇,聚焦 Java 语言最核心的设计理念和基础概念。适合 Java 初学者建立正确的知识框架,也适合有经验的开发者回顾基础。
一、Java 是什么?
1.1 Java 的定位
Java 既是一门编程语言,也是一个生态平台:
- 作为语言:面向对象、静态类型、语法接近 C++ 但去掉了指针、手动内存管理和多重继承等最让人头疼的部分。
- 作为平台:围绕 Java 形成了庞大的生态系统——Spring 框架、MyBatis 持久层、Hadoop 大数据、Kafka 消息队列、Android 开发……几乎所有大型企业的后端系统都离不开 Java 技术栈。
如今,Java 广泛应用于以下领域:
| 领域 | 典型技术栈 |
|---|---|
| 企业级后端开发 | Spring Boot + MyBatis + MySQL |
| 大数据处理 | Hadoop、Spark、Flink |
| 消息中间件 | Kafka、RocketMQ、RabbitMQ |
| 微服务与云原生 | Spring Cloud、Docker、Kubernetes |
| Android 移动开发 | Android SDK(Kotlin 也逐渐成为主流) |
1.2 Java 语言有哪些特点?
Java 的设计哲学是 "简单、安全、可移植",具体体现在以下方面:
① 简单易学
Java 的语法脱胎于 C++,但刻意去掉了那些容易出错又难掌握的特性:
- 没有指针(
*和&),不用操心内存地址 - 没有多重继承,用接口(
interface)替代 - 没有运算符重载(
+对字符串拼接是唯一的例外) - 自动垃圾回收(Garbage Collection),不用手动
free内存
// C++ 中你需要手动管理内存:
// int* p = new int(42);
// delete p; // 忘记这行就会内存泄漏!
// Java 中你只需要:
Integer p = 42;
// 不用操心释放,GC 会在合适的时机回收② 面向对象
Java 是一门纯正的面向对象语言,核心是三个概念:
- 封装:用
private/public/protected控制访问权限,隐藏内部实现细节 - 继承:子类复用父类的属性和方法(
extends) - 多态:同一个方法调用,不同对象表现出不同的行为
// 多态示例
class Animal {
void sound() { System.out.println("动物发出声音"); }
}
class Dog extends Animal {
void sound() { System.out.println("汪汪汪"); }
}
class Cat extends Animal {
void sound() { System.out.println("喵喵喵"); }
}
// 同一个 sound() 方法,不同对象行为不同
Animal myPet = new Dog();
myPet.sound(); // 输出: 汪汪汪③ 平台无关性:一次编译,到处运行
这是 Java 最响亮的口号,下一节会详细展开。核心思想是:Java 源码编译成 .class 字节码文件,任何安装了 JVM 的平台都能运行同一份字节码。
④ 支持多线程
Java 在语言级别内置了多线程支持,不需要调用操作系统的线程 API:
// 方式一:继承 Thread 类
class MyThread extends Thread {
public void run() {
System.out.println("线程运行中:" + Thread.currentThread().getName());
}
}
// 方式二:实现 Runnable 接口(更推荐)
class MyRunnable implements Runnable {
public void run() {
System.out.println("线程运行中:" + Thread.currentThread().getName());
}
}
new MyThread().start();
new Thread(new MyRunnable()).start();🐛 补充说明:C++11(2011 年发布)开始,C++ 也引入了标准多线程库
<thread>。所以"C++ 没有内置多线程"已经是老黄历了。
⑤ 可靠性
- 强类型检查:编译期就能发现很多类型错误,而不是等到运行时崩溃
- 异常处理:
try-catch-finally机制强制开发者思考错误情况 - 自动垃圾回收:消除内存泄漏和野指针问题
try {
int result = 10 / 0; // 会抛出 ArithmeticException
} catch (ArithmeticException e) {
System.out.println("发生了除零错误:" + e.getMessage());
} finally {
System.out.println("无论是否异常,这里都会执行");
}⑥ 安全性
Java 设计了多层安全防线:
- 编译期:类型检查、访问权限修饰符(
private方法外部无法调用) - 类加载期:字节码校验器验证
.class文件没有被恶意篡改 - 运行期:安全管理器(SecurityManager)可以限制程序访问文件系统、网络等资源
⑦ 编译与解释并存
Java 不是纯粹的编译型语言,也不是纯粹的解释型语言——后面会详细解释这个巧妙的"混合模式"设计。
⑧ 强大的生态
如果说 Java 语言本身是一辆好车,那它的生态就是覆盖全国的高速公路网。Spring、MyBatis、Netty、Hadoop、Kafka、Elasticsearch……这些开源项目让 Java 开发者可以站在巨人的肩膀上快速构建复杂系统。
二、⭐️ 一次编译,到处运行
2.1 为什么 Java 能做到跨平台?
传统的编译型语言(如 C/C++)直接把源码编译成特定平台的机器码。这意味着你在 Windows 上编译出的 .exe 文件,无法直接放到 Linux 上运行——必须拿到 Linux 上重新编译一次。
Java 走了完全不同的路线:
┌─────────────┐ javac 编译 ┌─────────────┐
│ Hello.java │ ──────────────────▶ │ Hello.class │
│ (源码) │ │ (字节码) │
└─────────────┘ └──────┬──────┘
│
┌────────────────────┼────────────────────┐
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ JVM │ │ JVM │ │ JVM │
│ Windows │ │ Linux │ │ macOS │
└──────────┘ └──────────┘ └──────────┘关键创新在于字节码(Bytecode):一种介于 Java 源码和机器码之间的"中间语言"。它不属于任何特定的 CPU 或操作系统,而是定义在 JVM 规范中的一套标准指令集。
2.2 跨平台还是 Java 最大的优势吗?
说实话,在 2026 年的今天,跨平台已经不是 Java 最独特的卖点了:
- Docker 容器化:把应用和依赖打成镜像,在哪儿都能跑,这比 JVM 的跨平台更彻底(连操作系统差异都抹平了)
- Go、Rust 等新语言:交叉编译也很方便,一条命令就能编译出不同平台的可执行文件
- Python/Node.js:解释型语言天然跨平台
那么 Java 真正的核心竞争力是什么?是它无与伦比的生态:
- 🏭 企业级开发标准:Spring 全家桶几乎定义了 Java 后端开发的方式
- 📊 大数据领域事实标准:Hadoop、Spark、Flink 都是 Java/Scala 生态
- 💬 消息中间件:Kafka(LinkedIn 开源,基石级基础设施)用 Java 写的
- 🔍 搜索引擎:Elasticsearch 基于 Java 的 Lucene
- 🧰 海量的第三方库:Maven 中央仓库超过 1000 万个构件
"一次编译到处运行"是 Java 崛起的原因,但成熟稳定的生态才是它屹立不倒的原因。
三、⭐️ JVM、JDK、JRE 的关系
3.1 JVM(Java Virtual Machine)
JVM 是一台"虚拟的计算机",它不运行 C 或 C++ 编译出的机器码,只运行 Java 字节码。
JVM 的核心职责:
| 子系统 | 功能 |
|---|---|
| 类加载器(Class Loader) | 把 .class 文件加载到内存中 |
| 运行时数据区 | 管理方法区、堆、栈、程序计数器等内存区域 |
| 执行引擎 | 解释执行字节码,或通过 JIT 编译器把热点代码编译为机器码 |
| 垃圾回收器(GC) | 自动回收不再使用的对象占用的内存 |
JVM 并不是只有一种实现!我们平时开发用的 HotSpot VM 只是 Oracle/Sun 提供的一种 JVM 实现。除此之外还有:
- OpenJ9:IBM 开发,启动快、内存占用小
- GraalVM:Oracle 实验室出品,支持多语言混合运行(Java + JS + Python + ...)
- Zing VM:Azul 公司开发,主打超低延迟 GC(号称可以处理 TB 级堆内存)
只要实现了 JVM 规范,任何人都可以开发自己的 JVM。
3.2 JRE(Java Runtime Environment)
JRE 是运行 Java 程序所需的最小环境。
JRE = JVM + Java 核心类库
核心类库包括:
├─ java.lang (String、Math、System……最基础的类)
├─ java.util (集合框架、日期时间、工具类)
├─ java.io (文件读写、输入输出流)
├─ java.net (网络通信、HTTP、Socket)
├─ java.sql (数据库操作)
└─ ... 还有很多 ...如果你只是要运行别人写好的 Java 程序(比如 Minecraft 游戏、Eclipse IDE),装 JRE 就够了。但从 JDK 11 开始,Oracle 不再单独提供 JRE 下载——要么装完整的 JDK,要么用 jlink 工具自己裁剪一个精简运行时。
3.3 JDK(Java Development Kit)
JDK 是开发 Java 程序所需的完整工具包。
JDK = JRE + 开发工具
开发工具包括:
├─ javac ── Java 编译器,把 .java 编译成 .class
├─ java ── 启动 JVM 运行程序
├─ javadoc ── 从源码注释生成 API 文档
├─ jar ── 打包工具,把多个 .class 打成 .jar 包
├─ jdb ── Java 调试器
├─ javap ── 反编译 .class 文件,查看字节码
├─ jconsole ── 图形化监控 JVM 内存、线程、类加载
└─ jlink ──(JDK 9+)生成自定义运行时镜像💡 JDK 9 的重要变化——模块系统(Project Jigsaw):JDK 本身被拆分成了 94 个模块。你可以用
jlink工具只打包程序实际用到的模块,生成一个精简的运行时。这大大减少了 Docker 镜像中 Java 部分的体积。
3.4 一张图搞懂三者关系
┌─────────────────────────────────────────┐
│ JDK │
│ ┌───────────────────────────────────┐ │
│ │ JRE │ │
│ │ ┌─────────────────────────────┐ │ │
│ │ │ JVM │ │ │
│ │ │ ┌────────┐ ┌────────────┐ │ │ │
│ │ │ │类加载器 │ │运行时数据区│ │ │ │
│ │ │ └────────┘ └────────────┘ │ │ │
│ │ │ ┌────────┐ ┌────────────┐ │ │ │
│ │ │ │执行引擎 │ │ 垃圾回收器 │ │ │ │
│ │ │ └────────┘ └────────────┘ │ │ │
│ │ └─────────────────────────────┘ │ │
│ │ ┌─────────────────────────────┐ │ │
│ │ │ Java 核心类库 │ │ │
│ │ └─────────────────────────────┘ │ │
│ └───────────────────────────────────┘ │
│ ┌───────────────────────────────────┐ │
│ │ 开发工具: javac jar javadoc ... │ │
│ └───────────────────────────────────┘ │
└─────────────────────────────────────────┘🎯 安装建议:作为开发者,直接安装 JDK 即可,因为 JDK 本身就包含了 JRE 和 JVM。目前长期支持(LTS)版本推荐 JDK 17 或 JDK 21。
四、⭐️ 编译与解释并存
面试中有一个经典问题:"Java 是编译型语言还是解释型语言?"
答案是:两者都是。
4.1 Java 程序的执行过程详解
Java 从源码到真正执行,经历了三个阶段:
┌──────────┐ javac 编译 ┌──────────┐ JVM 解释执行 ┌──────────┐
│ .java │ ────────────────▶ │ .class │ ────────────────▶ │ 机器码 │
│ 源文件 │ (编译阶段) │ 字节码 │ (运行阶段) │ CPU执行 │
└──────────┘ └──────────┘ └──────────┘
│ ▲
│ JIT 编译热点代码 │
└──────────────────────────────┘
(运行阶段优化)阶段一:编译(Compilation)
javac 编译器把 .java 源文件编译成 .class 字节码文件。这个阶段会做:
- 语法检查(少了分号?括号没配对?)
- 类型检查(把 String 赋给 int?不通过)
- 泛型擦除(编译后
List<String>和List<Integer>是同一个类型) - 生成字节码指令
阶段二:解释执行(Interpretation)
JVM 启动后,逐条读取字节码指令,翻译成当前平台的机器码执行。但每次都翻译很慢——如果一段代码被反复调用(比如循环 100 万次),每次都翻译也太浪费了。
阶段三:JIT 编译(Just-In-Time Compilation)
JVM 会监控哪些方法被频繁调用(称为"热点代码"),达到一定阈值后,JIT 编译器(如 HotSpot 的 C1/C2 编译器)直接把这段字节码编译成机器码并缓存起来。之后再调用这个方法时,直接执行缓存的机器码,速度大幅提升。
// 这个循环第一次执行时靠解释器
// 执行多次后,JIT 会把它编译成机器码,后面直接飞起
for (int i = 0; i < 1_000_000; i++) {
computeSomething(i);
}这种"混合模式"的设计非常精妙:启动时用解释器快速响应,运行时用 JIT 持续优化——既保证了启动速度,又能让长期运行的程序达到接近 C++ 的性能。
4.2 三种类型的对比
| 类型 | 代表语言 | 工作方式 | 启动速度 | 峰值性能 | 跨平台 |
|---|---|---|---|---|---|
| 编译型 | C、C++、Go、Rust | 源码 → 编译器 → 机器码 | 快 | 最高 | 需重新编译 |
| 解释型 | Python、JS、Ruby | 源码 → 解释器逐行执行 | 快 | 较慢 | ✅ |
| 混合型 | Java、C# | 源码 → 字节码 → 解释+JIT | 中等 | 接近编译型 | ✅ |
💡 现代语言的边界越来越模糊:Python 有 PyPy(JIT),JavaScript 有 V8(JIT),Go 虽然编译成机器码但也有自己的 GC 运行时。Java 的混合模式不是唯一解,但绝对是最成熟的设计之一。
4.3 AOT 编译是什么?
除了 JIT,Java 还有 AOT(Ahead-Of-Time Compilation,预编译) 这条路:
- JIT:运行时编译,"一边跑一边优化"
- AOT:部署前编译,"先把所有代码都翻译好再跑"
AOT 的优势是启动极快(不需要预热),缺点是不能做运行时优化(JIT 可以根据实际运行数据做激进的内联和去虚拟化)。GraalVM 的 Native Image 技术就是 AOT 的典型应用,适合 Serverless、微服务等对启动速度敏感的场景。
五、Java SE、Java EE、Java ME
Java 有三个"版本",它们的关系不是"升级",而是"分工":
| 版本 | 全称 | 定位 | 现状 |
|---|---|---|---|
| Java SE | Standard Edition | 基础平台,提供核心类库和 JVM | 一切的基础,永远活跃 |
| Java EE | Enterprise Edition | 企业级扩展,定义了一系列规范 | 2017 年捐给 Eclipse 基金会,改名 Jakarta EE |
| Java ME | Micro Edition | 嵌入式/移动设备 | 随着功能手机一起消亡,基本没人用了 |
SE 和 EE 的关系:
Java SE(地基) Java EE(大楼)
┌─────────────┐ ┌─────────────────────────┐
│ 核心类库 │ │ Servlet ── 处理 HTTP 请求│
│ JVM │ ──▶ │ JPA ── 数据库映射 │
│ 基础工具 │ │ JMS ── 消息队列 │
│ 集合框架 │ │ JTA ── 分布式事务 │
│ IO/网络 │ │ DI ── 依赖注入 │
│ 并发编程 │ │ Bean Validation ── 校验 │
└─────────────┘ └─────────────────────────┘Java EE 不是具体的软件,而是一套规范(Specification)。不同的厂商(Oracle、Red Hat、Apache 等)提供各自的实现。
六、第一个 Java 程序:不止是 Hello World
每一个 Java 程序员都是从下面这段代码开始的:
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, Java!");
}
}这段代码只有 5 行,但包含了 Java 程序最核心的要素。让我们逐行拆解:
6.1 public class HelloWorld
public:访问修饰符,表示这个类对外公开,任何其他类都可以访问class:声明这是一个类(Class)。Java 中一切代码都必须写在类里面——没有全局函数,没有全局变量HelloWorld:类名。文件名必须和 public 类名完全一致(包括大小写),所以这个文件必须是HelloWorld.java
6.2 public static void main(String[] args)
这一行被称为 main 方法签名,是 Java 程序的唯一入口。JVM 启动时,会找到这个 main 方法并开始执行。
每个关键字都有其必要性:
public:JVM 从外部调用 main 方法,所以必须是 publicstatic:程序刚启动时还没有任何对象存在,所以 main 必须是静态方法(属于类本身,不需要实例化)——JVM 通过HelloWorld.main(args)直接调用void:main 方法执行完程序就结束了,不需要返回值main:JVM 规定入口方法必须叫main(约定)String[] args:命令行参数数组,允许用户在启动程序时传入参数
# 编译
javac HelloWorld.java
# 运行并传入参数
java HelloWorld 你好 Java 2026
# 在程序中,args = ["你好", "Java", "2026"]如果你改一下程序,就能看到参数:
public class HelloWorld {
public static void main(String[] args) {
System.out.println("参数个数:" + args.length);
for (int i = 0; i < args.length; i++) {
System.out.println("第" + i + "个参数:" + args[i]);
}
}
}6.3 System.out.println("Hello, Java!")
System:java.lang包中的一个类,提供系统级别的工具(标准输入/输出、系统属性、环境变量等),被 JVM 自动导入out:System 类的一个静态字段,类型是PrintStream,代表标准输出流(默认指向控制台)println():PrintStream 的方法,打印一行内容并自动换行
💡 小知识:
java.lang包是唯一一个 JVM 会自动导入的包。所以你可以直接写System而不需要import java.lang.System。
七、总结
这篇文章覆盖了 Java 最核心的几个基础概念。在进入语法细节之前,先理解"Java 到底是什么"、"它如何运行"、"它的生态结构是怎样的",会让后续的学习更加顺畅。
| 概念 | 一句话记忆 |
|---|---|
| Java 的定位 | 一门面向对象的语言 + 一个庞大的生态平台 |
| 跨平台原理 | 源码 → 字节码 → 各平台 JVM 分别执行 |
| JVM | 运行字节码的虚拟计算机,有 HotSpot、GraalVM 等多种实现 |
| JRE | JVM + 核心类库,能运行但不能开发 |
| JDK | JRE + 编译/调试等工具,开发必装 |
| 编译与解释 | javac 编译为字节码,JVM 解释执行,JIT 热点编译优化 |
| JIT vs AOT | JIT 运行时优化(启动慢、峰值快);AOT 预编译(启动快、无运行时优化) |
| Java SE vs EE | SE 是地基(核心类库+JVM);EE 是企业级规范(Servlet/JPA/JMS) |
下一篇我们将进入 Java 基本语法——注释、标识符、关键字、运算符。
参考
- Java SE Specifications — Oracle 官方 Java SE 规范
- The Java Virtual Machine Specification — JVM 官方规范
- JavaGuide — 常看的Java知识分享社群