Elytra
Blog编程语言

Java 的三十年:从 Oak、JVM 到 Kotlin

从嵌入式设备上的 Oak 到企业后端与 Android:梳理 Java 的由来、主要版本语言特性、JVM 执行模型,以及 Kotlin 为什么能在 Java 生态中成长。

Java 已经三十多年了。

它经历过浏览器 Applet 的繁荣与消失,经历过桌面程序、功能手机、企业服务器和 Android,又从“写法古老”的印象里重新长出 Lambda、record、模式匹配与虚拟线程。今天说“Java”,我们可能同时在说三件不同的东西:

  • 一门刻意保持克制的编程语言;
  • 一套标准库和开发工具组成的平台;
  • 一个让 Java、Kotlin、Scala 等语言共同运行的虚拟机生态。

只看语法,很难解释 Java 为什么能活这么久;只谈 JVM,也会错过它近年来明显加快的语言演进。本文试着把这几条线重新接起来。

如果你还想从另一侧比较 JVM 与 .NET 的平台路线,可以接着读 .NET 的平台弯路。

资料范围

本文资料整理截至 2026 年 9 月 25 日。

  • 最新正式功能版是 Java 27,于 2026 年 9 月发布。
  • 按 Oracle 的支持路线,最新长期支持版是 Java 25 LTS;下一个计划中的 LTS 是 Java 29。1
  • Kotlin 当前稳定版是 2.4.20。Kotlin/JVM 默认生成兼容 Java 8 的字节码,也可显式选择更高的 JVM target;截至本文日期,官方列出的上限是 26。23

Java 27 是“最新”,不等于生产项目都应立刻升级到 27;企业项目通常更关注所用 JDK 发行版对 LTS、补丁和框架的支持。

1从 Oak 到 Java:它最早不是为 Web 发明的

Java 的前身叫 Oak。它最初面向嵌入式消费电子设备,由 James Gosling 在 Sun Microsystems 的 Green 项目中设计。后来团队发现早期设备市场没有按预期成熟,才把方向转向互联网,并将语言重新命名、调整为我们后来认识的 Java。早期语言规范对这段转向有明确记载。4

这个出身解释了 Java 最重要的设计目标:

设备和操作系统各不相同
        ↓
编译到统一的中间格式
        ↓
每个平台实现自己的虚拟机
        ↓
同一份程序在不同机器上运行

1995 年,Java 随 Web 浪潮公开亮相;1996 年发布的 Java 1.0 把“简单、面向对象、健壮、安全、架构中立、可移植”写进了平台的自我描述。5

当时最吸引眼球的是 Applet:浏览器下载字节码,再在沙箱中执行交互程序。Applet 后来退出历史舞台,但支撑它的核心思想——稳定的二进制格式、运行时验证、跨平台虚拟机——并没有消失。真正活到今天的,不是“网页里的小程序”,而是 Java 平台。

2006 年,Sun 开始把 HotSpot、javac 与 JDK 的主要代码以开源方式发布,OpenJDK 逐渐成为 Java 开发的共同上游。2010 年 Oracle 完成对 Sun 的收购,也成为 Java 的主要维护者之一。67

2先拆开几个经常混用的名字

名称它是什么典型内容
Java language编程语言类、接口、泛型、Lambda、record、模式匹配
JVM虚拟机规范及其实现加载、验证和执行 .class 字节码,管理内存与线程
Java SE标准平台规范语言、JVM、java.* 标准 API
JDK开发工具包JVM、标准库、javac、java、javadoc、jlink 等
JRE传统上的运行环境JVM + 运行所需类库;现代 JDK 发行方式中不一定单独提供

这里最容易犯的错误,是把 JVM 当成“Java 解释器”。JVM 首先是一份抽象机器规范;HotSpot 才是最常见的具体实现。一个 JVM 可以先解释字节码,也可以把热点代码即时编译为机器码,甚至采用 AOT 等其他实现策略。规范并不要求某一种固定执行方式。8

3主要版本:Java 是怎样一点点变成现代语言的

Java 的版本号经历过一次品牌变化:1.2 到 1.4 常被称为 Java 2,1.5 对外改称 Java 5,此后使用整数版本号。2017 年 Java 9 之后,JDK 进入大约每六个月一个功能版本的节奏;这不意味着每半年都必须迁移生产系统,LTS 仍然承担长期落点。

版本时间代表性的语言与平台变化
1.01996类、接口、异常、线程、GC、字节码与跨平台运行模型
1.11997内部类;JDBC、反射、RMI、JavaBeans 等平台能力成熟
1.2 / Java 21998Collections Framework、Swing;平台开始形成完整桌面与基础类库体系
1.42002assert;NIO、正则表达式、日志等标准库能力
52004泛型、注解、枚举、自动装箱、增强 for、可变参数、静态导入
62006语言变化很少,重点转向性能、工具、Web Services 与平台成熟度
72011try-with-resources、菱形语法、字符串 switch、multi-catch;JVM 加入 invokedynamic
82014Lambda、方法引用、接口默认方法;Stream、Optional、java.time
92017模块系统 JPMS、JShell、集合工厂方法;版本发布节奏改变
102018-03局部变量类型推断 var
11 LTS2018-09Lambda 参数可用 var;标准 HTTP Client,长期维护的新基线
14–172020–2021switch 表达式、文本块、record、instanceof 模式匹配、sealed class 先后稳定;17 为 LTS
18–212022–2023UTF-8 成为默认字符集;record pattern、模式匹配 switch;Java 21 LTS 正式加入虚拟线程
222024-03未命名变量与模式 _ 稳定;FFM API 稳定,连接原生函数与堆外内存
23–242024–2025语言侧以预览迭代为主;24 加入正式 Class-File API,继续推进启动与运行时能力
25 LTS2025-09模块导入声明、紧凑源文件与实例 main、灵活构造函数体稳定
26–272026无新的永久语言特性;primitive pattern matching 继续预览,运行时、库与安全能力仍持续演进

版本日期与 Java 9 之后的正式/预览语言特性,可在 Oracle 的语言变更总表与 Java SE 规格页交叉核对。910

这张表很长,但 Java 的语言演进其实可以压缩成四次明显转向。

4Java 5:让类型系统和框架真正长大

Java 5 是第一轮大改造。此前集合通常存放 Object,取出时再强制转换:

List names = new ArrayList();
names.add("Duke");
String name = (String) names.get(0);

有了泛型:

List<String> names = new ArrayList<>();
names.add("Duke");
String name = names.get(0);

泛型把很多错误提前到编译期,也成为集合、依赖注入、ORM 与现代框架 API 的基础。但 Java 为了兼容既有字节码,采用了 类型擦除:大多数泛型实参不会作为对象的运行时类型保存,编译器会擦除类型参数、插入必要的转换,并生成 bridge method。11

这带来几个延续至今的限制:

new T();                    // 不允许
value instanceof List<String>; // 不允许检查具体泛型实参
List<int> values;           // primitive 不能直接作为类型实参

同一版本的注解也极为重要。今天常见的 Spring、JUnit、Jackson、Android 与编译期代码生成,都大量依赖注解和反射/处理器建立声明式模型。Java 5 看起来只是加了几组语法,实际上为后来的框架文化搭好了骨架。

5Java 8:从“只有类”走向函数式组合

Java 8 是另一座分水岭。它没有放弃面向对象,而是把函数式表达能力接进了已有的接口系统。

Java 7 时代:

Collections.sort(users, new Comparator<User>() {
    @Override
    public int compare(User a, User b) {
        return a.name().compareTo(b.name());
    }
});

Java 8:

users.sort(Comparator.comparing(User::name));

List<String> activeNames = users.stream()
    .filter(User::active)
    .map(User::name)
    .sorted()
    .toList();

这里不是简单把匿名类缩短成箭头:

  • 函数式接口让 Lambda 可以适配既有的单一抽象方法接口;
  • 接口默认方法允许给已有接口增加能力,同时尽量保持二进制兼容;
  • Stream API提供内部迭代、惰性流水线与并行处理模型;
  • 方法引用让已有对象模型与函数式组合自然连接。

Java 8 也解释了 Java 的典型演进方式:不另起一套互不兼容的语言,而是在旧抽象上寻找一条能让历史代码继续工作的扩展路径。

Stream 不等于集合,也不保证更快

Stream 是一次性消费的计算流水线,不是存储数据的容器。它擅长表达筛选、映射、聚合;parallelStream() 也不会自动让业务更快。数据规模、拆分成本、共享状态与所用线程池,都会影响结果。

6Java 9 之后:模块、半年发布与 Preview

Java 9 的 JPMS 模块系统试图解决 JDK 和大型应用长期存在的几个问题:依赖边界模糊、内部 API 被随意访问、运行镜像过大。module-info.java 可以显式声明需要什么、导出什么:

module com.example.order {
    requires java.sql;
    exports com.example.order.api;
}

模块化让 JDK 能用 jlink 组合出更小的运行镜像,也加强了内部包封装;代价是从 Java 8 迁移时,反射框架、深度依赖 JDK 内部 API 的库经常需要调整。

更深远的变化是发布方式。过去一个大版本可能等待多年;Java 9 之后,功能可以在较短周期内交付,并通过 Preview Feature 反复获取反馈。

Preview 不是“文档写得还不完整”,而是有意暂未永久承诺的语言或 VM 特性。它需要显式启用,也可能修改甚至撤回。String Templates 在 Java 21、22 预览后于 23 撤回,就是很好的例子。9

快发布,不等于激进定型

Java 现在的节奏更快,但语言设计仍然保守:一个特性可以连续多个版本预览,直到语义和迁移成本足够清楚。半年发布解决的是“等待交付太久”,Preview 解决的是“不要太早把设计永久写进语言”。

7Java 14–21:数据建模、模式匹配与虚拟线程

现代 Java 最明显的变化,是过去冗长的“数据类 + 类型判断”开始被语言直接表达。

7.1record:数据载体不再手写样板代码

record User(long id, String name, String email) {}

编译器会生成组件访问器、构造器、equals、hashCode 和 toString。record 不是“字段可以随便改的 Lombok 类”,而是明确表达:这个类型的主要语义来自声明中的数据状态。Record 在 Java 16 正式交付。12

7.2sealed class + pattern matching:封闭领域模型

sealed interface Result permits Success, Failure {}

record Success(String value) implements Result {}
record Failure(int code, String message) implements Result {}

String describe(Result result) {
    return switch (result) {
        case Success(var value) -> value;
        case Failure(var code, var message) -> code + ": " + message;
    };
}

sealed hierarchy 告诉编译器子类型集合是受控的,record pattern 把数据解构出来,模式匹配 switch 则检查分支是否穷尽。这让 Java 能更自然地表达编译器 AST、协议消息、状态机和业务结果。

7.3虚拟线程:保留阻塞式写法,改变线程成本

Java 21 正式加入 Virtual Threads。它们仍然是 java.lang.Thread,但不再要求每个 Java 线程在整个生命周期中独占一个操作系统线程。JVM 把大量虚拟线程调度到较少的平台线程上,适合存在大量等待的 I/O 服务。13

try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10_000; i++) {
        executor.submit(() -> fetchRemoteData());
    }
}

它的价值不是让 CPU 密集算法凭空加速,而是让“一个请求一个线程”的直线式代码,在高并发 I/O 场景中不再需要同样数量的昂贵 OS 线程。

8Java 25:一边降低入门门槛,一边修补老限制

Java 25 LTS 的三个正式语言特性很能说明今天的方向。

紧凑源文件与实例 main 让初学者不必先理解 public static void main(String[] args) 的全部仪式:

void main() {
    IO.println("Hello, Java");
}

模块导入声明可以一次导入某个模块导出的包:

import module java.base;

灵活构造函数体允许在 super(...) 或 this(...) 之前进行不访问当前实例的参数验证与准备工作:

final class PositiveBigInteger extends BigInteger {
    PositiveBigInteger(long value) {
        if (value <= 0) throw new IllegalArgumentException("value <= 0");
        super(Long.toString(value));
    }
}

这些变化没有 Java 8 Lambda 那样轰动,却在处理真实摩擦:让第一段 Java 更短,让模块 API 更容易使用,让构造器能在父类构造前可靠验证输入。它们在此前多个版本预览,直到 Java 25 才稳定。14

9JVM 到底做了什么

一段 Java 或 Kotlin 程序在 HotSpot 上运行,可以先画成这条简化路径:

Loading diagram…

9.1.class 才是 JVM 真正认识的语言

JVM 规范写得很直接:虚拟机并不了解 Java 语言本身,它只了解 class 文件格式。只要一门语言能生成合法字节码,就可以把 JVM 当成发布平台。8

这就是 Kotlin、Scala、Clojure、Groovy 能和 Java 共处的根本原因,也是 Java 生态真正的护城河:

不同源语言
  → 相同 class / JAR / 模块边界
  → 相同 GC、JIT、调试器、Profiler
  → 可以调用同一批 Java 类库

9.2类加载不只是“把文件读进来”

JVM 会经历加载、链接与初始化。链接又包含验证、准备、解析等阶段。字节码验证会检查结构和类型约束,避免把任意字节误当成可执行 JVM 指令;类加载器则让应用服务器、插件系统和框架能够建立相互隔离或动态扩展的类型空间。

同名类由不同类加载器加载时,可以被 JVM 视为不同类型。这是 Java 插件机制强大的来源,也是 ClassCastException、依赖冲突和容器泄漏中最让人头疼的一类问题。

9.3JIT:Java 为什么会“先热身,再变快”

HotSpot 通常不会在程序启动时把所有代码一次性编译到最高优化级别。它先解释或快速编译代码,并收集真实运行画像:哪些方法最热、分支通常走哪边、调用点实际上出现了哪些类型。随后 C1/C2 分层编译器可以做内联、逃逸分析、去虚拟化等优化。HotSpot 的分层编译默认使用 C1 与 C2。15

这解释了两个常见现象:

  • 微基准如果没有正确预热,很容易测到编译过程而非稳定吞吐;
  • 长期运行的服务可能获得很高的峰值性能,但传统 JVM 的启动时间和内存占用也会成为命令行工具、Serverless 与小容器的痛点。

OpenJDK 的 Project Leyden 正在把更多类加载、链接、画像乃至部分编译工作前移,目标就是改善启动时间、达到峰值性能的时间和内存占用。16

9.4GC:自动管理内存,不等于没有内存问题

JVM 的堆由垃圾收集器回收不再可达的对象。具体算法不是 JVM 规范固定的一部分;HotSpot 可以提供面向吞吐、低停顿或超大堆的不同收集器。

自动回收解决的是“何时释放不可达对象”,不是“对象一定不会占太多内存”。缓存无上限、监听器不注销、ThreadLocal 生命周期过长、类加载器仍被引用,都可以造成逻辑上的内存泄漏。理解可达性、分配速率和 GC 日志,仍然是大型 Java 服务的基本功。

10Kotlin 为什么会出现

Kotlin 由 JetBrains 在 2010 年启动,2016 年发布 1.0。它不是因为 JVM 失败才出现,恰恰相反:JVM、Java 类库和构建生态已经很成功,但 Java 语言在很多日常表达上显得冗长。 Kotlin 选择保留平台,替换上层语言体验。2

一个典型 Java 数据类型:

record User(String name, String email) {
    String displayName() {
        return email == null ? name : name + " <" + email + ">";
    }
}

对应 Kotlin:

data class User(
    val name: String,
    val email: String?,
) {
    fun displayName(): String =
        email?.let { "$name <$it>" } ?: name
}

现代 Java 的 record 已经缩小了样板代码差距,但 Kotlin 的重点仍然很明确:

  • String 与 String? 在类型系统中区分非空与可空;
  • data class 自动提供值语义常用成员和 copy;
  • 属性、默认参数、命名参数减少 getter/setter 和重载;
  • extension function 在不修改原类的情况下增加调用形式;
  • smart cast 根据控制流自动收窄类型;
  • sealed class/interface 与 when 适合封闭状态建模;
  • suspend 与 kotlinx.coroutines 提供结构化的异步编程模型。

Kotlin 后来也发展到 JavaScript、Native、Wasm 与 Multiplatform,但 Kotlin/JVM 仍然是它最成熟、最容易理解的落点:编译器生成 Java 兼容的 class 文件,运行在同一个 JVM 上。

11Kotlin 与 Java 怎样互操作

Kotlin 从设计之初就重视 Java 互操作。大多数 Java 类可以直接在 Kotlin 中调用,Java 也能创建和调用 Kotlin 编译出的类。JavaBean getter/setter 在 Kotlin 中通常表现为属性,Java SAM interface 可以直接接收 Kotlin Lambda。17

val executor = Executors.newSingleThreadExecutor()
executor.execute { println("running") } // Runnable SAM conversion

这种兼容性让团队不必重写整个项目:同一个 Gradle/Maven 工程里可以逐个文件、逐个模块迁移。Android 的 Kotlin-first 路线也建立在这一点上——Google 优先为 Kotlin 提供新的示例与扩展,同时继续支持 Java API。18

但“可互调”不等于“语义完全相同”。

11.1Platform type:空安全边界上的妥协

普通 Java 签名未必说明一个引用能否为 null。Kotlin 导入时会形成 platform type;调用者可以把它当可空或非空使用,编译器无法提供纯 Kotlin 代码里同样强的保证。

// Java:没有 nullability annotation
String findName();
val name = legacy.findName() // 可能被推断为平台类型 String!
println(name.length)         // 若 Java 实际返回 null,仍可能在运行时失败

因此混合项目里的 nullability annotation、清晰 API 边界和渐进迁移,比“把文件扩展名全改成 .kt”更重要。

11.2默认参数、属性与伴生对象会映射成 JVM 结构

Kotlin 的属性通常编译成字段加 getter/setter;默认参数依赖编译器生成的调用约定,Java 调用者若需要传统重载,常用 @JvmOverloads;伴生对象、顶层函数、值类等也各有自己的字节码映射与 @JvmStatic、@JvmName 等互操作工具。

如果一个库主要给 Java 用户使用,API 设计者最好从 Java 侧实际调用一次,而不是只看 Kotlin 源码是否优雅。

11.3泛型并没有因为换成 Kotlin 就获得完整运行时实化

Kotlin/JVM 同样运行在现有 JVM 泛型模型上,普通泛型仍然擦除。Kotlin 的 inline + reified 能让特定内联函数在调用点保留类型实参操作,但它不是把所有 JVM 泛型都变成了具化泛型。17

12Kotlin 协程与 Java 虚拟线程,不是同一个东西

这两者都能让高并发代码更易读,因此经常被放在一起比较,但抽象层级不同。

Kotlin coroutineJava virtual thread
核心抽象可挂起、恢复的计算java.lang.Thread 的轻量实现
调度由 coroutine dispatcher / library 控制由 JVM 虚拟线程调度器映射到平台线程
API 风格suspend、scope、launch、async阻塞式 Thread / Executor API
生态接入调用链需要理解 suspending API大量既有阻塞 API 可直接使用
取消与结构化并发kotlinx.coroutines 已有成熟模型Structured Concurrency 仍在 Java 平台持续预览

Kotlin 的 suspend 是语言能力,但 launch、async、dispatcher 等主要来自 kotlinx.coroutines 库;协程最终仍在线程上运行,挂起时可以释放线程去做别的工作。19

虚拟线程则让传统阻塞式代码获得更低的线程成本。它不自动提供 Kotlin coroutine scope 的全部生命周期语义,也不会让 CPU 密集任务突破核心数限制。

怎么选

  • 已有 Java/Spring 同步代码,希望少改动获得高 I/O 并发:先评估虚拟线程。
  • Android、Compose 或已经围绕 suspending API 设计的 Kotlin 项目:协程通常更自然。
  • 新系统不要只看“能开多少任务”;取消传播、超时、监控、ThreadLocal/上下文传递和第三方库行为同样重要。

13今天该选 Java,还是 Kotlin

这不是“旧语言与新语言”之间的单选题,因为二者大量共享同一个运行时和生态。

13.1更适合优先考虑 Java 的情况

  • 团队、框架和运维体系已经以 Java 为共同语言;
  • 公共库需要面对最广泛的 JVM 使用者;
  • 希望减少编译器插件、额外运行库和跨语言调试复杂度;
  • 项目更看重长期兼容、人员供给与升级可预测性;
  • Java 17/21/25 的 record、pattern matching、virtual threads 已经满足主要需求。

13.2更适合优先考虑 Kotlin 的情况

  • Android 与 Jetpack Compose 开发;
  • 业务模型大量受益于空安全、sealed hierarchy、extension 与 DSL;
  • 团队愿意统一 Kotlin 风格、构建设置和 Java 互操作规范;
  • 已经使用协程生态,且能让异步边界从 UI/API 一直贯穿到数据层;
  • 需要在 JVM 之外探索 Kotlin Multiplatform,同时接受各目标平台成熟度不同。

真正需要避免的,是在没有边界规则时随意混写:Java API 暴露模糊的 nullability,Kotlin API 生成难用的 Java 签名,两个异步模型再互相套娃。混合语言本身不是问题,没有明确的模块边界与互操作设计才是问题。

14Java 为什么能活到今天

Java 的优势从来不只是某一个语法特性。它真正长期有效的组合是:

相对克制的语言演进
  + 稳定、版本化的 class 文件
  + 成熟的 JIT / GC / 诊断工具
  + 庞大的库、框架与工程人才
  + 很强的二进制兼容意识

这种克制也有代价。类型擦除、primitive 与 object 的分裂、启动和预热成本,都不是靠几行语法糖能消失的问题。OpenJDK 仍在通过 Valhalla 探索更紧凑的值/原始类型与泛型,通过 Leyden 改善启动、预热和占用;这些工程之所以漫长,正是因为 Java 不愿轻易牺牲已经运行几十年的代码。2016

Kotlin 的出现并没有推翻这套平台,反而证明了它的价值:当上层语言不够顺手时,团队可以换一种语言,继续使用 JVM、Java 类库、构建工具和部署体系。

收束

Java 的故事不是“一门 1990 年代语言勉强活到现在”,而是三层系统彼此托举:

  1. Java language 用克制的方式持续吸收泛型、Lambda、record、模式匹配与更轻量的并发;
  2. JVM 把源码语言与机器、操作系统隔开,并用 JIT、GC 与稳定字节码承担平台价值;
  3. Kotlin 等 JVM 语言 在不丢掉生态的前提下,继续试探更现代的表达方式。

Java 最成功的发明,也许不是某个关键字,而是把“语言”和“运行平台”分开。Oak 消失了,Applet 消失了,很多框架也会消失;只要 .class、JVM 与兼容性承诺仍然成立,这个生态就还能继续演化。

注释

  1. Oracle,Java SE Support Roadmap,更新于 2026-09-15。列出 Java 25 为 LTS、Java 27 为 2026 年 9 月非 LTS 功能版,以及后续支持计划;具体免费使用与商业支持期限取决于发行版和许可。 ↩

  2. Kotlin Documentation,FAQ。说明 Kotlin 项目始于 2010 年、1.0 发布于 2016 年,以及截至本文日期的稳定版 2.4.20。 ↩ ↩2

  3. Kotlin Documentation,FAQ: Which versions of JVM does Kotlin target?。说明 Kotlin/JVM 默认生成 Java 8 兼容字节码,并列出当前可选 JVM target 范围。 ↩

  4. Oracle,《Java Language Specification》第一版前言,Preface to the First Edition。说明 Java 原名 Oak、最初面向嵌入式消费电子,并在后来转向互联网。 ↩

  5. James Gosling、Henry McGilton,1996,The Java Language Environment。早期官方白皮书列出简单、健壮、安全、架构中立、可移植等设计目标。 ↩

  6. OpenJDK Wiki,JBS Overview。记录 2006 年 HotSpot 与 javac 开源、2007 年 JDK 7 大部分源码发布的时间线。 ↩

  7. Oracle,2010,Oracle and Sun Overview。记录 Oracle 于 2010 年 1 月完成对 Sun Microsystems 的收购。 ↩

  8. Oracle,《Java Virtual Machine Specification 25》,Introduction。说明 JVM 是抽象机器、只认识 class 格式而不认识 Java 源语言,并允许其他语言以 JVM 为目标平台。 ↩ ↩2

  9. Oracle,Java Language Changes Summary。汇总 Java 9–27 的正式、预览及撤回语言特性。 ↩ ↩2

  10. Oracle,Java SE Specifications。列出 Java SE 25、26、27 的正式规格与发布日期,支撑本文“最新正式版 Java 27”的判断。 ↩

  11. Oracle Java Tutorials,Type Erasure。说明 Java 编译器如何擦除泛型参数、插入转换并生成 bridge method。 ↩

  12. OpenJDK,JEP 395: Records。记录 record 在 JDK 16 正式交付的设计目标与语义。 ↩

  13. OpenJDK,JEP 444: Virtual Threads。说明虚拟线程在 Java 21 正式交付、M:N 调度目标,以及其适合高吞吐 I/O 而非提升 CPU 密集计算速度。 ↩

  14. Oracle,Significant Changes in JDK 25。说明模块导入、紧凑源文件与实例 main、灵活构造函数体在 Java 25 稳定。 ↩

  15. Oracle,Java HotSpot Virtual Machine Performance Enhancements。说明 HotSpot 默认的 C1/C2 分层编译及运行时画像优化。 ↩

  16. OpenJDK,Project Leyden。项目目标是改善 Java 程序的启动时间、达到峰值性能的时间和占用,并列出已交付与进行中的 AOT 工作。 ↩ ↩2

  17. Kotlin Documentation,Calling Java from Kotlin 与 Calling Kotlin from Java。说明属性映射、SAM 转换、platform type 与泛型擦除等互操作规则。 ↩ ↩2

  18. Android Developers,Android's Kotlin-first approach。说明 Android 自 2019 年采用 Kotlin-first 的工具、文档与 API 方向,同时继续支持 Java。 ↩

  19. Kotlin Documentation,Coroutines basics。说明 suspend 属于语言,而大多数协程能力来自 kotlinx.coroutines;协程在 JVM 上仍运行于线程并可在挂起时释放线程。 ↩

  20. OpenJDK,State of Valhalla: Background。设计说明介绍扁平化值类型与 specialized generics 的目标;属于进行中的 OpenJDK 项目,不代表已经进入正式 Java 语言。 ↩

CONTINUE EXPLORING

沿着这篇文章继续

在地图中查看

On this page