bigywater.tech
Java · 166

Java 模块系统:module-info.java 如何限制访问

module-info.java 里的 exports、opens、requires 分别管什么?这篇用三个真实模块,从编译期、运行时反射、命令行参数和 JDK 自己的封装四个层面逐项验证(ServiceLoader 的 provides/uses 见前面一篇,Module Layer 在后面)。

not visible
直接用未导出的包时 javac 的报错
IllegalAccessException
反射访问未导出包里的类
54 / 67
java.base 无限制导出 / 限定导出的包数

编译期

实测 · 本机执行输出
  [other2 直接用 lib.friend] 编译失败:package lib.friend is not visible | (package lib.friend is declared in module lib, which does not export it to module other2) | 1 error
  [app 直接用未导出的 lib.internal] 编译失败:package lib.internal is not visible | (package lib.internal is declared in module lib, which does not export it) | 1 error

运行时与反射

实测 · 本机执行输出
  直接用导出的包 lib.pub.Pub → pub.hi
  用 exports ... to app 导出给我的包 lib.friend.Friend → friend.hi
  反射加载未导出的包里的类 lib.internal.Hidden 并 newInstance → IllegalAccessException: class app.Main (in module app) cannot access class lib.internal.Hidden (in module lib) because module lib does not export lib.internal to module app
  反射对 lib.internal.Hidden 的 public 方法 hi() 调用 → IllegalAccessException: class app.Main (in module app) cannot access class lib.internal.Hidden (in module lib) because module lib does not export lib.internal to module app
  对 opens 的包里的类,setAccessible 读私有字段 → opened-secret

requires 不等于访问权

实测 · 本机执行输出
  other 模块反射创建 lib.friend.Friend → IllegalAccessException: class other.Main (in module other) cannot access class lib.friend.Friend (in module lib) because module lib does not export lib.friend to module other

--add-opens

实测 · 本机执行输出
  反射加载未导出的包里的类 lib.internal.Hidden 并 newInstance → lib.internal.Hidden@728938a9
  反射对 lib.internal.Hidden 的 public 方法 hi() 调用 → hidden.hi

JDK 内部

实测 · 本机执行输出
  String.class 的私有字段 value:setAccessible → InaccessibleObjectException: Unable to make field private final byte[] java.lang.String.value accessible: module java.base does not "opens java.lang" to unnamed module @15db9742
  jdk.internal.misc.Unsafe.getUnsafe() → IllegalAccessException: class Main cannot access class jdk.internal.misc.Unsafe (in module java.base) because module java.base does not export jdk.internal.misc to unnamed module @15db9742
  sun.misc.Unsafe(jdk.unsupported 模块里 opens 的包)的 theUnsafe 可访问:true
  加上 --add-opens java.base/java.lang=ALL-UNNAMED 之后第一行:   String.value 可访问
  java --list-modules:这个 JDK 一共有 69 个模块;其中 java.base 的描述:
    java.base 无限制导出的包 54 个,限定导出(qualified exports … to …)的包 67 个

分步演示

Java 模块系统
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / OpenJDK(Temurin 17.0.20、Homebrew 21.0.12 与 27,每篇注明实际用的版本);用 javac 编译、java 直接运行,需要第三方库时用 Maven 解析依赖;计时用 System.nanoTime,数字每次运行会有小幅抖动。JDK 21.0.12
    • 没有验证:requires transitive 与 requires static、open module、自动模块(automatic module)与未命名模块的规则、--add-exports 与 --add-reads 的细节、jlink 与模块图裁剪(见后面的篇目)、JDK 17 与 27 对 sun.misc.Unsafe 的限制变化
    京ICP备2026067502号-1京公网安备11010502063487号