JDK JDK 学习手册8 → 27 · JDK 专用学习站
QUICKREF · MIGRATION · 8 → 11

从 8 迁移到 11

JDK 11 · 速查主题 06 / 06 · 预计 30 分钟
进阶30 分钟JEP 320JEP 335JEP 336
一句话JDK 11 是 8 之后的第一个 LTS。升级的主要风险不是新语法,而是移除的 Java EE / CORBA 模块、Nashorn 与 Pack200 的弃用、G1 成为默认 GC,以及反射访问与 --release 的边界。它比 17 宽松:JDK 11 默认仍允许非法反射访问,只是警告。

学完你要能自己回答

  1. JDK 11 移除了哪些 Java EE / CORBA 模块?Nashorn、CMS、Pack200 是移除还是弃用?
  2. --release 11 与 -source 8 -target 8 的区别是什么?为什么升级时优先用 --release?
  3. JDK 11 的 --illegal-access 默认值是什么?它和 JDK 17 的强封装有什么区别?

先对齐版本坐标01

从 8 升到 11,先确认四件事:源码级别、class 文件版本、默认 GC、依赖里是否用了已移除的 Java EE API。JDK 11 的 class 文件版本是 55,默认 GC 是 G1(JDK 9 起)。

项目JDK 8JDK 11迁移影响
class 文件5255低版本 JVM 无法加载 55
默认 GCParallelG1停顿特征变化,需重新压测
模块系统无JPMS(9 起)模块路径、强封装、--add-opens
Java EE / CORBA内置移除(JEP 320)JAXB/JAX-WS 等需外部依赖
Nashorn内置弃用15 才移除;11 仍可运行
HttpClientHttpURLConnectionjava.net.http新客户端可用,旧 API 仍在
var无10 起可用局部变量类型推断
java -version
javac -version
openjdk version "11.0.28" 2025-07-15 LTS
OpenJDK Runtime Environment Microsoft-11913448 (build 11.0.28+6-LTS)
OpenJDK 64-Bit Server VM Microsoft-11913448 (build 11.0.28+6-LTS, mixed mode, sharing)
javac 11.0.28

升级顺序建议 8 → 11 → 17,把 11 当作检查点。直接 8 → 17 会把 Java EE 移除、强封装、CMS 移除等问题叠在一起,定位成本更高。

JEP 320:Java EE 与 CORBA 模块被移除02

JDK 11 移除了随 JDK 分发的 Java EE 与 CORBA 模块。很多在 JDK 8 上能编译的代码,在 11 上直接找不到包;这不是模块路径配置问题,而是模块本身不存在。

被移除的模块 / API典型包替代方案
java.xml.bind(JAXB)javax.xml.bind.*jakarta.xml.bind-api + 实现
java.xml.ws(JAX-WS / SAAJ)javax.xml.ws.*、javax.xml.soap.*jakarta.xml.ws-api + CXF / Metro
java.activationjavax.activation.*jakarta.activation-api + 实现
java.xml.ws.annotationjavax.annotation.*(Common Annotations)jakarta.annotation-api
java.corbajavax.activity.*、org.omg.*没有内置替代;迁移到其他 RPC / 消息方案
java.transaction(JTA)javax.transaction.*jakarta.transaction-api
java.se.ee 聚合模块—不再存在;不要再用 --add-modules java.se.ee
import javax.xml.bind.DatatypeConverter;

public class JaxbUse {
    public static void main(String[] args) {
        System.out.println(DatatypeConverter.printHexBinary(new byte[]{1, 2}));
    }
}
error: package javax.xml.bind does not exist
import javax.xml.bind.DatatypeConverter;
^
error: cannot find symbol
  symbol:   variable DatatypeConverter
try {
    Class.forName("javax.xml.bind.JAXBContext");
} catch (ClassNotFoundException e) {
    System.out.println("missing=" + e.getMessage());
}
try {
    Class.forName("org.omg.CORBA.ORB");
} catch (ClassNotFoundException e) {
    System.out.println("corba=missing");
}
missing=javax.xml.bind.JAXBContext
corba=missing

注意 java.transaction.xa 仍然存在,javax.transaction.xa.*(XA 接口)没有随 JTA 一起移除。不要因为看到 javax.transaction 就以为所有事务 API 都没了。

javax.annotation.processing 仍在 java.compiler 模块中;被移除的是 Common Annotations 的 javax.annotation.Resource、PostConstruct、PreDestroy 等。包名相同不代表模块相同。

弃用不是移除:Nashorn、Pack200、CMS03

JDK 11 的很多「移除」其实是弃用。把 11 当成 17/21 来清理,会误删仍可用的能力;反过来,把弃用当成永久可用,也会在升级到 15/17 时踩坑。

能力JDK 11 状态移除版本迁移建议
Nashorn JavaScript弃用,仍可运行15(JEP 372)改用 GraalJS 等外部引擎
Pack200 / unpack200弃用,工具仍在14(JEP 367)改用 jar / jlink
CMS GC弃用,仍可启动14(JEP 363)改用 G1;大堆低延迟评估 ZGC
Thread.stop/suspend/resume弃用,仍可调用后续版本限制改为 interrupt / 协作式取消
finalize()仍可用,尚未弃用18 弃用try-with-resources / Cleaner
SecurityManager仍可用17 弃用,后续禁用不要在新代码中依赖
import javax.script.*;

public class NashornDemo {
    public static void main(String[] args) throws Exception {
        ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
        System.out.println("engine=" + (engine == null ? "null" : engine.getClass().getName()));
        if (engine != null) {
            System.out.println("eval=" + engine.eval("1 + 2"));
        }
    }
}
Warning: Nashorn engine is planned to be removed from a future JDK release
engine=jdk.nashorn.api.scripting.NashornScriptEngine
eval=3

这段输出证明 Nashorn 在 JDK 11 仍然可用,只是会打印弃用警告。到 JDK 15,getEngineByName("nashorn") 返回 null,而不是启动失败。

java -XX:+UseConcMarkSweepGC -version
java -XX:+PrintGCDetails -version
java -XX:MaxPermSize=256m -version
OpenJDK 64-Bit Server VM warning: Option UseConcMarkSweepGC was deprecated in version 9.0 and will likely be removed in a future release.
[0.007s][warning][gc] -XX:+PrintGCDetails is deprecated. Will use -Xlog:gc* instead.
OpenJDK 64-Bit Server VM warning: Ignoring option MaxPermSize; support was removed in 8.0.
JDK 11 不会因为 CMS / PrintGCDetails / MaxPermSize 拒绝启动;JDK 21 才会。迁移到 11 时可以先保留这些参数观察,但应在 17 之前清理。

反射访问:JDK 11 还是 permit,不是 17 的强封装04

JDK 9 起 JDK 内部 API 被模块封装,但 JDK 9–15 默认仍是宽松模式:第一次非法反射访问会打印警告,然后放行。JDK 11 的默认值是 --illegal-access=permit,不是 deny。

import java.lang.reflect.Field;

public class Reflect {
    public static void main(String[] args) throws Exception {
        Field f = String.class.getDeclaredField("value");
        f.setAccessible(true);
        System.out.println("opened=" + (f.get("abc") != null));
    }
}
java Reflect
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by Reflect to field java.lang.String.value
WARNING: Please consider reporting this to the maintainers of Reflect
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
opened=true
java --illegal-access=deny Reflect
Exception in thread "main" java.lang.reflect.InaccessibleObjectException:
  Unable to make field private final byte[] java.lang.String.value accessible:
  module java.base does not "opens java.lang" to unnamed module
java --illegal-access=deny --add-opens java.base/java.lang=ALL-UNNAMED Reflect
opened=true
JDK默认行为开关说明
9–15permit:警告后放行--illegal-access=permit|warn|deny|debugJDK 11 属于这一档
16deny:默认拒绝--illegal-access 仍可用JEP 396
17+deny,开关移除只能用 --add-opens / --add-exportsJEP 403

--add-opens 打开的是深度反射权限,--add-exports 打开的是编译期/运行期的普通访问权限。两者都不是长期方案:优先升级依赖、替换内部 API,把参数限制到最小包和模块。

在 JDK 11 上用 --illegal-access=deny 跑一遍测试,是成本很低的「17 预演」。如果这时大量报 InaccessibleObjectException,应尽早处理,而不是等到升级 17。

--release 11:把 API 边界编译进构建05

--release 11 不仅设置 class 文件版本,还使用 JDK 11 自带的 API 快照检查你只用了 Java 11 标准库。-source 8 -target 8 只约束语法和字节码版本,仍然可以调用 JDK 11 的新 API。

public class OnlyBlank {
    public static void main(String[] args) {
        System.out.println(" ".isBlank());
    }
}
# 能编译,class 版本 52,但运行时可能 NoSuchMethodError
javac -source 8 -target 8 -d st8 OnlyBlank.java

# 编译期就拒绝:isBlank 不在 Java 8 API 中
javac --release 8 -d r8 OnlyBlank.java
-source 8 -target 8: 编译通过(只有 bootstrap class path 警告),class major 52
--release 8: error: cannot find symbol
  symbol:   method isBlank()
  location: class String

JDK 11 的 javac 支持 --release 6 到 --release 11(6 会提示 obsolete,但仍可编译)。项目里应统一用 --release 11;Maven 配 maven.compiler.release=11,Gradle 配 options.release = 11。

# 依赖与 API 排查
jdeps --jdk-internals app.jar
jdeprscan --release 11 app.jar

# JFR 在 11 已开源,可直接启动录制
java -XX:StartFlightRecording=duration=60s,filename=app.jfr -jar app.jar

# 确认 TLS 1.3(JDK 11 默认支持)
java TlsDemo
  1. 把所有运行时(本机、CI、容器、K8s)统一到 JDK 11,确认 java -version 与 javac -version 一致。
  2. 用 --release 11 编译,打开 -Xlint:removal,先让弃用与移除警告可见。
  3. 跑 jdeps --jdk-internals,列出仍在使用 sun.* / JDK 内部 API 的依赖。
  4. 替换 Java EE / CORBA 依赖,把 javax.* 迁到 jakarta.* 或显式第三方实现。
  5. 清理启动脚本中的 MaxPermSize、CMS、PrintGCDetails 等旧参数;在 11 上它们可能只是警告,到 17 会变成启动失败。
  6. 用 --illegal-access=deny 跑测试,提前暴露反射访问问题。
  7. 最后再评估模块化:先把应用跑稳在 classpath,再逐个模块化,不要一次性重写。
升级到 11 不等于必须模块化。JDK 11 仍支持 classpath 应用;模块路径是可选能力,先把依赖和反射问题清理干净,收益更直接。

版本边界BOUNDARY

这张表比 API 本身更值得记。写代码时先确认你的运行时版本。

特性 / API状态说明
Java EE / CORBA 模块11 移除JEP 320;JAXB/JAX-WS/activation/Common Annotations/CORBA/JTA 需外部依赖。
java.transaction.xa11 保留XA 接口仍在;不要把它和 JTA 一起删掉。
Nashorn11 弃用 / 15 移除11 仍可运行,会打印弃用警告。
Pack20011 弃用 / 14 移除工具仍在,计划移除。
CMS GC9 弃用 / 14 移除JDK 11 仍可用;21 上会拒绝启动。
--illegal-access 默认11 permit警告后放行;16 默认 deny,17 移除开关。
--release9 起提供JDK 11 支持 --release 6..11;优先于 -source/-target。
G1 默认 GC9 起JDK 11 默认 G1,不再是 Parallel。
TLS 1.311 支持JEP 332;默认启用的协议列表包含 TLSv1.3。
ZGC11 实验 / 15 正式需要 UnlockExperimentalVMOptions;11 仅 Linux/x64。

费曼自检SELF CHECK

先合上页面,用自己的话回答,再展开对照。能讲出因果和反例,才算真正掌握。

01. JDK 11 移除了哪些 Java EE 模块?
JEP 320 移除了 java.xml.bind(JAXB)、java.xml.ws(JAX-WS/SAAJ)、java.activation、java.xml.ws.annotation(Common Annotations)、java.corba、java.transaction 以及 java.se.ee 聚合模块;需要显式引入 Jakarta 或第三方实现。
02. --release 11 和 -source 8 -target 8 的区别是什么?
--release 11 使用 JDK 11 的 API 快照(ct.sym)限制可用 API,能阻止调用 Java 12+ 的 API;-source/-target 只改变语法和 class 版本,仍可能链接到 JDK 11 的新 API,运行时才失败。
03. JDK 11 的 --illegal-access 默认值是什么?
默认是 permit:第一次非法反射访问打印警告,然后放行。JDK 16 改为默认 deny,JDK 17 移除该开关,只能使用 --add-opens / --add-exports。
04. Nashorn 在 JDK 11 被移除了吗?
没有。JDK 11 只是弃用,仍可通过 getEngineByName("nashorn") 获取并执行脚本,同时打印弃用警告;JDK 15 才移除。
学习进度 记录保存在本机浏览器 · 不上传

JDK 学习手册 · JDK / Java 专用学习站 · 纯静态 · 双击 index.html 即可使用

本站专注 JDK 版本演进与 Java 教学,非 Oracle / OpenJDK 官方站点。版本数据来自 OpenJDK 官方 Features 表;课程示例已在对应本机 JDK 实测。构建日期 2026-11-12。