获得了一个仍然支持Java 6的项目。下面的代码位于使用Compiler compliance level 1.6构建的jar文件中
应该从为java 6或更新版本构建的java应用程序中调用该jar文件。 它在Java 8中运行良好。
现在使用Java9,我遇到了nio.DirectByteBuffer的问题,我尝试用这种方式解决它,使用反射:
@SuppressWarnings("unchecked")
static void cleanDirectBuffer(sun.nio.ch.DirectBuffer buffer) {
if (JAVA_VERSION < 1.9) {
sun.misc.Cleaner cleaner = buffer.cleaner();
if (cleaner != null) cleaner.clean();
} else {
// For java9 do it the reflection way
@SuppressWarnings("rawtypes")
Class B = buffer.getClass();
// will be a java.nio.DirectBuffer, which is unknown if compiled in 1.6 compliance mode
try {
java.lang.reflect.Method CleanerMethod = B.getMethod("cleaner");
CleanerMethod.setAccessible(true); // fails here !
Object cleaner = CleanerMethod.invoke(buffer);
if (cleaner == null) return;
@SuppressWarnings("rawtypes")
Class C = cleaner.getClass();
java.lang.reflect.Method CleanMethod = C.getMethod("clean");
CleanMethod.invoke(cleaner);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (Exception other) {
other.printStackTrace();
}
}
}
JAVA_VERSION检测很好并且可以很好地切换,具体取决于我的调用代码使用的版本。 jre6到jre8环境很好地使用sun.misc.Cleaner路径,但这在java9中不起作用
您可能会注意到我不是java.reflection的专家。
通过猜测,我找到了.setAccessible(true);
和lance-java的回答(感谢到目前为止)有点帮助:
版本2:
Class B = buffer.getClass();
try {
java.lang.reflect.Method CleanerMethod = B.getDeclaredMethod("cleaner");
CleanerMethod.setAccessible(true);
Object cleaner = CleanerMethod.invoke(buffer);
if (cleaner == null) return;
@SuppressWarnings("rawtypes")
Class C = cleaner.getClass();
java.lang.reflect.Method CleanMethod = C.getDeclaredMethod("clean");
CleanMethod.setAccessible(true); // Now it fails here !
CleanMethod.invoke(cleaner);
} catch (InaccessibleObjectException e) {
// ** causes: Unable to make public void jdk.internal.ref.Cleaner.clean() accessible: module java.base does not "exports jdk.internal.ref" to unnamed module **
}
此外警告第一个CleanerMethod.setAccessible(true)
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by my.package.MyClass (file:/xyz.jar) to method java.nio.DirectByteBuffer.cleaner()
...
WARNING: All illegal access operations will be denied in a future release
......听起来不太健康?但唉,这只是一个警告:)
我还缺少什么,或者我的问题有不同/更好的方法?
答案 0 :(得分:6)
在Java 9中引入了模块概念(https://blog.codefx.org/java/java-module-system-tutorial/)。
模块列出它导出的包。对于一个模块中的代码(比如org.codefx.demo.jpms)来访问另一个模块中的代码(比如java.base中的String),必须满足以下可访问性规则:
访问类型(String)必须是公共的
包含类型(java.lang)的包必须由其模块(java.base)
导出访问模块(org.codefx.demo.jpms)必须读取访问过的模块(java.base),这通常是通过要求它来实现的
如果在编译或运行时违反了这些规则中的任何一个,则模块系统会抛出错误。这意味着公众不再是公开的。非导出包中的公共类型与导出包中的非公共类型一样,外部世界无法访问。还要注意反射失去了超级大国。
现在可以定义可在包外部访问的类/方法。即使它们是公共的,其他模块也无法访问所有其他非指定的类/方法。这是指向module-info
http://people.redhat.com/mbalaoal/webrevs/jdk_8029661_tls_12_sunpkcs11/2018_02_02/8029661.webrev.02/src/java.base/share/classes/module-info.java.html java.base
的链接。如您所见jdk.internal.ref
仅导出到这些模块:java.desktop
和jdk.unsupported
答案 1 :(得分:2)
sun.nio.ch.DirectBuffer
和java.nio.DirectByteBuffer
是内部JDK的一部分,因此您不应该依赖这些类。它们随时都会消失。
如果您希望清除它们,请不要引用DirectByteBuffer
。
答案 2 :(得分:0)
Class.getMethod()
,Class.getField()
等只会返回公共方法/字段。我想你想要Class.getDeclaredMethod()
。