在同一包中子类化 sun.* 类会产生 IllegalAccessError

Posted

技术标签:

【中文标题】在同一包中子类化 sun.* 类会产生 IllegalAccessError【英文标题】:Subclassing sun.* class in same package gives IllegalAccessError 【发布时间】:2013-12-18 07:43:20 【问题描述】:

前言:

    我要向您展示的内容是错误的,而且我很清楚通过做这种愚蠢的事情来破坏封装是多么糟糕。 我不想解决任何更一般的 I/O 问题。这只是一个实验。

我正在尝试对 sun.nio.ch.SourceChannelImpl 进行子类化,这是包私有类,JDK 中存在包私有构造函数(在 rt.jar 中),所以我必须在 sun.nio.ch 包中创建它。

这是我的子类:

package sun.nio.ch;
import java.io.FileDescriptor;
import java.nio.channels.spi.SelectorProvider;
class MySourceChannel extends SourceChannelImpl 
  public MySourceChannel(SelectorProvider sp, FileDescriptor fd) 
    super(sp, fd);
  

这是我的简单测试:

package sun.nio.ch;
import java.io.FileDescriptor;
public class Main 
  public static void main(String[] args) 
    new MySourceChannel(null, FileDescriptor.in);
  

这就是失败:

Exception in thread "main" java.lang.IllegalAccessError: class sun.nio.ch.MySourceChannel cannot access its superclass sun.nio.ch.SourceChannelImpl
        at java.lang.ClassLoader.defineClass1(Native Method)
        at java.lang.ClassLoader.defineClass(ClassLoader.java:800)
        at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
        at java.net.URLClassLoader.defineClass(URLClassLoader.java:449)
        at java.net.URLClassLoader.access$100(URLClassLoader.java:71)
        at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
        at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
        at sun.nio.ch.Main.main(Main.java:5)

这可能不是 你不能在 JDK 包 XYZ 中定义类 ((java|sun).*) 类型的问题,否则我会得到

java.lang.SecurityException: Prohibited package name: XYZ

Main 类在这个包中运行良好。

我还尝试通过设置Policy 允许一切来禁用安全检查,但这也无济于事。我也尝试过System.setSecurityManager(null);(我不确定这是否真的禁用了它)但它也没有帮助。

有什么问题?请问怎么解决?

我已经用 JDK 1.7.0_45 进行了尝试,包括 Oracle 和 OpenJDK。

【问题讨论】:

【参考方案1】:

SourceChannelImpl 是一个“包私有”类。在 JVM 中,包总是由单个类加载器加载。如果你有两个由不同类加载器加载的同名包,它们就不是同一个包。

您可以通过使用-Xbootclasspath/a:mybootspath 在引导类加载器中加载部分或全部代码来解决此问题。

【讨论】:

以上是关于在同一包中子类化 sun.* 类会产生 IllegalAccessError的主要内容,如果未能解决你的问题,请参考以下文章

Java 子类与继承

20165210 Java第四周学习总结

在同一包和目录中找不到符号

20175226 2018-2019-2 《Java程序设计》第四周学习总结

java 面对对象的三大特性

重写和重载