"大翔在技术选型会上把咖啡杯往桌上一顿:'Java,1995年活到现在,全世界的后端都在跑,咱们飞翔科技凭什么不用?'白歌不紧不慢地接话:'关键是Write Once, Run Anywhere——一套代码,Windows开发、Linux部署,不用改。'台下的产品经理孔蓝眼睛亮了:'那我们的'飞翔运动'App后端是不是也能一套搞定?'"
Java语言概述
本章定位
深入理解Java语言的起源、设计哲学、平台体系,以及JDK 8为何成为Java生态的里程碑版本。这是整个Java SE教程的"世界观"文件。
Java的诞生:从一棵橡树到全球语言
历史背景
1991年,Sun Microsystems公司的James Gosling(詹姆斯·高斯林)领导的"Green Project"团队开始研发一种面向消费电子设备(如机顶盒、PDA)的编程语言。最初命名为Oak(橡树),因Gosling办公室窗外的一棵橡树而得名。后来发现Oak已被注册为商标,团队在一次咖啡馆的头脑风暴中,将语言改名为Java——源自印度尼西亚爪哇岛的咖啡。
1995年5月23日,Sun Microsystems在SunWorld大会上正式发布了Java 1.0。伴随着Netscape Navigator浏览器宣布支持Java Applet,Java一炮而红。
关键时间线:
- 1991年:Green Project启动,Oak语言诞生
- 1995年:Java 1.0正式发布,"Write Once, Run Anywhere"口号提出
- 1998年:Java 2发布,分为J2SE/J2EE/J2ME三大平台
- 2010年:Oracle以74亿美元收购Sun Microsystems
- 2014年:JDK 8发布——Java历史上最重要的LTS版本
- 2018年:JDK 11 LTS发布,Java改为半年一个版本
核心人物
| 人物 | 角色 | 贡献 |
|---|---|---|
| James Gosling | Java之父 | 领导Green Project,设计Java语言 |
| Bill Joy | Sun联合创始人 | 支持并推动Java项目 |
| Patrick Naughton | Green Project成员 | 参与初始语言设计 |
| Oracle | 现任维护者 | 2010年收购Sun,继续发展Java生态 |
核心理念:Write Once, Run Anywhere
"一次编写,到处运行"——这不仅是Java的口号,更是它最根本的设计哲学。
传统语言的跨平台困境
在Java出现之前,C/C++等语言需要针对不同操作系统和CPU架构分别编译:
Java的解决方案:在操作系统和应用程序之间插入一层JVM(Java Virtual Machine,Java虚拟机)。Java源代码被编译为与平台无关的字节码(Bytecode),由各个平台的JVM负责将字节码翻译为本地机器指令。程序员只需写一套代码、编译一次,就可以在任何安装了JVM的设备上运行。
字节码:跨平台的秘密
| 层次 | 格式 | 可读性 | 可移植性 |
|---|---|---|---|
| 源代码 | 纯文本 .java | 人类可读 | 依赖编码和语言版本 |
| 字节码 | 二进制 .class | JVM可读(可用javap -c反编译查看) | 跨平台 |
| 本地机器码 | CPU指令 | 机器可读 | 与CPU架构绑定 |
字节码(Bytecode)是Java实现跨平台的关键中间层。它是一组紧凑的、与CPU架构无关的指令,由JVM解释执行或在运行时通过JIT编译器转换为本地机器码。每个
.class文件开头固定为十六进制的CA FE BA BE(魔数),这是Java字节码的身份标识。
三大平台:Java SE / Java EE / Java ME
Java不仅仅是一门语言,而是一个庞大的技术生态。Oracle(及之前的Sun)将其分为三大平台:
| 平台 | 全称 | 定位 | 典型场景 |
|---|---|---|---|
| Java SE | Standard Edition | 核心基础,所有Java开发者的起点 | 桌面应用、命令行工具、基础后端服务 |
| Java EE(现Jakarta EE) | Enterprise Edition | 企业级Web/分布式应用 | 飞翔科技的电商网站、学生管理系统后端 |
| Java ME | Micro Edition | 嵌入式与移动设备 | 早期功能手机、智能卡、物联网传感器 |
注意:2017年,Oracle将Java EE移交给了Eclipse基金会,并更名为Jakarta EE。但Java SE始终是三者中最核心的部分——无论你将来学EE还是Android,SE的功底决定你的上限。
JDK 8:Java生态的里程碑
为什么JDK 8如此重要?
2014年3月发布的JDK 8是Java历史上首个**LTS(Long-Term Support,长期支持)**版本,也是目前企业中使用最广泛的Java版本(截至2024年,仍有超过40%的生产环境运行在JDK 8上)。其核心新特性深刻改变了Java的编程范式:
| 新特性 | 说明 | 影响力 |
|---|---|---|
| Lambda表达式 | (x, y) -> x + y 简洁函数式写法 | ⭐⭐⭐⭐⭐ |
| Stream API | 声明式集合操作:list.stream().filter().map().collect() | ⭐⭐⭐⭐⭐ |
| 接口默认方法(default) | 接口中提供方法默认实现,不破坏已有实现类 | ⭐⭐⭐⭐ |
| 接口静态方法(static) | 接口中定义工具方法 | ⭐⭐⭐ |
| Optional | 空值安全容器,优雅处理null | ⭐⭐⭐⭐ |
| 新日期时间API(java.time) | 不可变、线程安全的LocalDate/LocalDateTime等 | ⭐⭐⭐⭐⭐ |
| 方法引用(::) | System.out::println 简化Lambda | ⭐⭐⭐⭐ |
JDK各LTS版本对比
| 版本 | 发布时间 | 关键意义 | 当前企业占比(估算) |
|---|---|---|---|
| JDK 8 | 2014年3月 | 首个LTS,Lambda/Stream革命 | ~40% |
| JDK 11 | 2018年9月 | 模块化成熟、HTTP Client标准 | ~25% |
| JDK 17 | 2021年9月 | Record/Sealed Class/Pattern Matching | ~20% |
| JDK 21 | 2023年9月 | Virtual Thread/Pattern Matching正式 | ~5%(增长中) |
本教程选择JDK 8的理由:它是Java函数式编程的起点,绝大多数企业面试基于JDK 8考察Lambda、Stream、并发编程,且向后兼容至JDK 21。掌握JDK 8,你就能读懂和维护80%以上的企业Java代码库。
代码示例
示例一:验证Java跨平台能力
白歌让大翔在不同操作系统上验证同一份Java代码的执行结果一致性。飞翔科技开发环境是Windows,生产服务器是Linux。
/**
* CrossPlatformDemo.java
* 演示:同一份Java代码在不同操作系统上的输出完全一致
* 场景:飞翔科技技术部验证Java跨平台能力
*/
public class CrossPlatformDemo {
public static void main(String[] args) {
// 获取当前操作系统信息
String osName = System.getProperty("os.name");
String osArch = System.getProperty("os.arch");
String javaVersion = System.getProperty("java.version");
String javaVendor = System.getProperty("java.vendor");
// 飞翔科技公司数据
String companyName = "广州飞翔科技";
System.out.println("═══════════════════════════════════");
System.out.println(" " + companyName);
System.out.println(" Java 跨平台验证报告");
System.out.println("═══════════════════════════════════");
System.out.println("操作系统名称 : " + osName);
System.out.println("操作系统架构 : " + osArch);
System.out.println("Java 版本 : " + javaVersion);
System.out.println("Java 厂商 : " + javaVendor);
System.out.println("───────────────────────────────────");
System.out.println("Java 运行时可用处理器数 : " + Runtime.getRuntime().availableProcessors());
System.out.println("Java 虚拟机最大内存(MB) : " + Runtime.getRuntime().maxMemory() / 1024 / 1024);
System.out.println("───────────────────────────────────");
// 跨平台核心验证:以下代码在任何OS上输出完全一致
int empCount = 12; // 飞翔科技员工总数
double revenue = 8888.88; // 示例数据
String slogan = "愿你朝华相顾,愿你前程似锦。";
System.out.println("公司员工总数 : " + empCount);
System.out.println("示例营收数据 : ¥" + revenue);
System.out.println("企业寄语 : " + slogan);
System.out.println("═══════════════════════════════════");
}
}
Windows 10 运行输出:
═══════════════════════════════════
广州飞翔科技
Java 跨平台验证报告
═══════════════════════════════════
操作系统名称 : Windows 10
操作系统架构 : amd64
Java 版本 : 1.8.0_202
Java 厂商 : Oracle Corporation
───────────────────────────────────
Java 运行时可用处理器数 : 8
Java 虚拟机最大内存(MB) : 1820
───────────────────────────────────
公司员工总数 : 12
示例营收数据 : ¥8888.88
企业寄语 : 愿你朝华相顾,愿你前程似锦。
═══════════════════════════════════
CentOS 7 运行输出(业务参数部分完全一致):
═══════════════════════════════════
广州飞翔科技
Java 跨平台验证报告
═══════════════════════════════════
操作系统名称 : Linux
操作系统架构 : amd64
Java 版本 : 1.8.0_202
Java 厂商 : Oracle Corporation
───────────────────────────────────
Java 运行时可用处理器数 : 4
Java 虚拟机最大内存(MB) : 910
───────────────────────────────────
公司员工总数 : 12
示例营收数据 : ¥8888.88
企业寄语 : 愿你朝华相顾,愿你前程似锦。
═══════════════════════════════════
注意:操作系统名称、处理器数量、最大内存等环境相关数据会不同,但业务逻辑代码的输出完全一致——这就是"Write Once, Run Anywhere"的本质。
示例二:JDK 8 Lambda表达式初体验
小崔第一次接触Lambda,用它来整理飞翔科技技术部的员工名单。
import java.util.*;
/**
* TeamListDemo.java
* 演示:JDK 8 Lambda 表达式 + Stream API 的简洁性
* 场景:小崔整理飞翔科技技术部员工名单
*/
public class TeamListDemo {
public static void main(String[] args) {
// 飞翔科技技术部员工名单(姓名,职位,年龄)
String[][] techTeam = {
{"大翔", "CEO/CTO", "32"},
{"白歌", "架构师", "29"},
{"小崔", "后端开发", "25"},
{"黄俪", "前端开发", "24"},
{"李眉", "运维工程师", "28"},
};
System.out.println("═══════════════════════════════════");
System.out.println(" 飞翔科技 · 技术部花名册");
System.out.println("═══════════════════════════════════");
// JDK 8 之前:传统 for 循环打印
System.out.println("\n【传统方式:for-i 循环】");
for (int i = 0; i < techTeam.length; i++) {
System.out.println(" " + techTeam[i][0] + " - " + techTeam[i][1]
+ "(" + techTeam[i][2] + "岁)");
}
// JDK 8:Lambda 表达式 + forEach
System.out.println("\n【JDK 8 方式:Lambda + forEach】");
Arrays.stream(techTeam)
.forEach(member -> System.out.println(
" " + member[0] + " - " + member[1] + "(" + member[2] + "岁)"
));
// JDK 8:Stream API 过滤 + 排序(找出30岁以下的员工,按姓名排序)
System.out.println("\n【JDK 8 Stream:30岁以下青年员工】");
Arrays.stream(techTeam)
.filter(member -> Integer.parseInt(member[2]) < 30)
.sorted(Comparator.comparing(member -> member[0]))
.forEach(member -> System.out.println(
" " + member[0] + " - " + member[1] + "(" + member[2] + "岁)"
));
System.out.println("\n 愿你朝华相顾,愿你前程似锦。");
System.out.println("═══════════════════════════════════");
}
}
运行输出:
═══════════════════════════════════
飞翔科技 · 技术部花名册
═══════════════════════════════════
【传统方式:for-i 循环】
大翔 - CEO/CTO(32岁)
白歌 - 架构师(29岁)
小崔 - 后端开发(25岁)
黄俪 - 前端开发(24岁)
李眉 - 运维工程师(28岁)
【JDK 8 方式:Lambda + forEach】
大翔 - CEO/CTO(32岁)
白歌 - 架构师(29岁)
小崔 - 后端开发(25岁)
黄俪 - 前端开发(24岁)
李眉 - 运维工程师(28岁)
【JDK 8 Stream:30岁以下青年员工】
小崔 - 后端开发(25岁)
李眉 - 运维工程师(28岁)
黄俪 - 前端开发(24岁)
愿你朝华相顾,愿你前程似锦。
═══════════════════════════════════
Java语言的核心特性
| 特性 | 说明 | 体现 |
|---|---|---|
| 面向对象 | 一切皆对象(除8种基本类型),支持封装/继承/多态/抽象 | class/interface/extends/implements |
| 跨平台 | 字节码 + JVM 屏蔽底层差异 | javac → .class → 任意OS运行 |
| 强类型 | 每个变量必须先声明类型,编译期类型检查 | int x = 10; String s = "hello"; |
| 自动内存管理 | JVM通过GC自动回收不再使用的对象 | 无需手动 free/delete |
| 多线程 | 语言级别内置线程支持 | Thread / Runnable / java.util.concurrent |
| 健壮性 | 编译期检查 + 运行时检查 + 异常处理体系 | try-catch-finally |
| 安全性 | 字节码校验、类加载器双亲委派、安全管理器 | 沙箱机制 |
| 动态性 | 反射机制允许运行时获取类信息并操作对象 | Class.forName() |
核心原理:JIT编译器与执行模式
Java程序的执行并非纯粹的解释执行,而是采用了混合模式(Mixed Mode):
关键阶段:
- 解释执行(冷启动):程序启动时,JVM使用解释器逐条执行字节码。这个阶段启动快但执行慢。
- 热点探测:JVM统计每个方法的调用次数和循环次数。当达到
-XX:CompileThreshold阈值(默认10000次),标记为"热点代码"。 - JIT编译:C1编译器(Client Compiler)快速编译,C2编译器(Server Compiler)深度优化。编译结果缓存在Code Cache中。
- 直接执行:后续调用直接执行编译后的机器码,性能显著提升。
- 逆优化:如果JIT编译时基于的假设不再成立(如类继承层次变化),则回退到解释执行。
这也是Java常被调侃"先慢后快"的原因——预热完成后,JDK 8 Server模式下的性能可以与C++相媲美。
易错场景与面试考点
反例:混淆JDK、JRE和JVM
小崔刚学Java时犯的经典错误:
# ❌ 错误:只装了JRE就想用javac编译
C:\Users\xiaocui> javac Hello.java
'javac' 不是内部或外部命令,也不是可运行的程序或批处理文件。
# 小崔挠头:"我不是装了Java吗?"
# 白歌看了一眼:"你装的是JRE,只能运行java命令,不能编译。"
# 李眉补刀:"也就是只能java Hello.class,不能javac Hello.java。"
原因分析:
JDK = JRE + 开发工具(javac、jar、javadoc等)
JRE = JVM + 核心类库(rt.jar等)
JVM = 字节码执行引擎
所以你装JRE → 有java命令(能运行)但没有javac命令(不能编译)
纠正:从Oracle官网下载JDK 8(而非JRE 8),安装后java -version和javac -version都应该能正常输出。
面试高频题
Q1:Java为什么能跨平台?
Java的跨平台依赖于两点:① Java源代码被编译为与平台无关的字节码(.class文件),而非特定CPU的机器码;② 每个平台都有各自的JVM实现,负责将字节码翻译为该平台的本地机器指令。JVM充当了抽象层,屏蔽了操作系统和硬件的差异。注意:JVM本身不是跨平台的——Windows版JVM和Linux版JVM是不同的程序,但它们向上提供的字节码执行接口是一致的。
Q2:JDK、JRE、JVM三者之间是什么关系?
JDK(Java Development Kit)是Java开发工具包,包含JRE + 编译工具(javac、jar、javadoc)。JRE(Java Runtime Environment)是Java运行环境,包含JVM + 核心类库。JVM(Java Virtual Machine)是Java虚拟机,负责加载和执行字节码。三者的包含关系:JDK ⊃ JRE ⊃ JVM。
Q3:JDK 8为什么被称为Java的"革命性"版本?
JDK 8引入了Lambda表达式和Stream API,使Java从纯面向对象语言转向支持函数式编程范式。此外,新日期时间API(java.time)解决了旧Date/Calendar的线程安全和设计缺陷;接口默认方法/静态方法让接口可进化而无需破坏现有实现。这些特性大幅减少了样板代码,提升了开发效率和代码可读性。在JDK 8之前,一个排序操作可能需要5-7行匿名内部类代码,JDK 8之后一行Lambda即可完成。
Q4:Java与C/C++的本质区别是什么?
① 编译方式:C/C++直接编译为本地机器码,与平台绑定;Java编译为字节码,在JVM上运行。② 内存管理:C/C++手动管理内存(malloc/free或new/delete),容易内存泄漏;Java由JVM的GC自动回收。③ 指针:C/C++支持指针运算,灵活但危险;Java没有指针概念(只有引用),更安全。④ 多重继承:C++支持多继承;Java通过接口实现多继承效果,避免菱形问题。⑤ 平台:C/C++面向特定平台编译;Java一次编译到处运行。
本章小结:Java诞生于1995年,核心理念是"Write Once, Run Anywhere",通过字节码和JVM实现跨平台。三大平台(SE/EE/ME)覆盖从桌面到企业到嵌入式的全场景。JDK 8(2014年发布)是Java生态的里程碑,引入了Lambda表达式和Stream API,至今仍是企业生产环境的主流版本。