【问题标题】:Unable to export a package from java.base module无法从 java.base 模块导出包
【发布时间】:2018-01-30 09:57:16
【问题描述】:

使用 IDEA-EAP 进行 JDK9 开发实验。

我收到以下错误 -

Error:(3, 20) java: package jdk.internal.misc is not visible  
(package jdk.internal.misc is declared in module java.base, which does
not export it to module com.jigsaw.npe)

类定义为 -

package experiment;
import jdk.internal.misc.Unsafe;

public class CompareAndSwap {

    static Unsafe UNSAFE = Unsafe.getUnsafe();
    ...
}

我尝试在使用 IDE 创建的模块中也包含一个 module-info.java 文件,其中包含以下语句 -

module com.jigsaw.npe {
    requires java.base;
}

目录结构现在如图所示 -

尽管 IDE 将 module-info.java 反映为未使用,这可能是我无法像上面尝试的那样定义 module com.jigsaw.npe 的原因。

寻求有关如何正确放置 module-info.java 和/或其他我错过的内容的帮助。

【问题讨论】:

  • @StefanZobel 该命令究竟做了什么,有什么先决条件吗?
  • 您的设置完全没问题,这与 IntelliJ 无关。我建议编辑问题(和标签)以删除该部分。

标签: java java-9 java-platform-module-system java-module module-info


【解决方案1】:

模块 java.base 没有 exportjdk.internal.misc.,因此类型 jdk.internal.misc.Unsafe 不是 accessible - 结果编译失败。

您可以通过添加以下命令行选项使其导出包:

# if you want to access it from com.jigsaw.npe only:
--add-exports java.base/jdk.internal.misc=com.jigsaw.npe
# if you want to access from all code:
--add-exports java.base/jdk.internal.misc=ALL-UNNAMED

您必须在编译 (javac) 时执行此操作在运行 (java) 代码时。

【讨论】:

  • --add-exports 不存在了
  • 是的,确实如此。拨打java -X看一看:--add-exports <module>/<package>=<target-module>(,<target-module>)*
  • yes 作为命令行选项,它确实存在,但是如果你用 --add-exports 设置 java 选项,它就不起作用,抱怨它是一个未知的命令行参数
  • "yes as option on command line" 这正是我所声称的,仅此而已。
  • @MartynasJusevičius "exports 指令指定当前模块要导出的包的名称。对于其他模块中的代码,这将在编译时和运行时授予访问权限..." ( JLS §7.7.2 - docs.oracle.com/javase/specs/jls/se18/html/jls-7.html#jls-7.7.2)
【解决方案2】:

Nicolai's answer 关于从 java.base 模块或任何其他模块导出其他未导出的包所需的技术是正确的。

但是如果目标是使用Unsafe,那么这样做的方法是使用sun.misc.Unsafe,它由jdk.unsupported 模块导出。如果您正在为未命名的模块编译代码,则无需对模块执行任何特殊操作即可访问它。如果你在一个模块中编译代码,你需要添加

requires jdk.unsupported;

到您的module-info.java 文件。

要使用Unsafe,您必须使用反射setAccessible 技术来访问该字段,这与您在以前的JDK 版本中必须执行的操作相同:

import sun.misc.Unsafe;

...

Field theUnsafeField = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafeField.setAccessible(true);
Unsafe theUnsafe = (Unsafe)theUnsafeField.get(null);

尽管Unsafe 位于jdk.unsupported 模块中,但根据JEP 260,JDK 9 支持此技术。

【讨论】:

  • warning: Unsafe is internal proprietary API and may be removed in a future release 怎么样?这两个功能不一样吗?
  • @reversiblean 不,“内部专有 API”警告实际上是一个不同的警告。它是在模块系统之前由 javac 发布的——至少我在使用 JDK 7 或 JDK 8 编译时看到它。因此,它与模块可访问性无关。发布它是因为 javac 可以看到程序正在访问 sun.* 命名空间中的类型,这些类型是内部专有 API,可能会发生变化。
  • 是的,我明白了。我的意思是,尽管可访问性不同,jdk.internal.misc.Unsafesun.misc.Unsafe 是否相同?
  • 不,它们是不同的。 sun.misc.Unsafejdk.unsupported 模块中,它导出。 jdk.internal.misc.Unsafejava.base 模块中,它被导出。 sun.misc.Unsafe 是内部的最小子集。这个想法是公开现有外部库和框架实际使用的最小不安全 API 集。由于添加了公开的、受支持的替换 API,API 将从 sun.misc.Unsafe 中删除。 jdk.internal.misc.Unsafe 继续发展,但它确实仅供内部使用。
猜你喜欢
  • 1970-01-01
  • 2019-07-31
  • 1970-01-01
  • 2023-02-20
  • 2017-12-14
  • 1970-01-01
  • 2019-07-03
  • 2018-11-12
  • 2023-01-31
相关资源
最近更新 更多