在同一个包中对sun。*类进行子类化会产生IllegalAccessError

时间:2013-12-02 14:45:36

标签: java inheritance visibility core sun

前言:

  1. 我要向你展示的是错误的,我很清楚我做这种愚蠢的事情是多么糟糕的打破封装。
  2. 我不是要解决任何更常见的I / O问题。这只是一个实验。
  3. 我正在尝试使用JDK中存在的包私有构造函数的包私有类子类sun.nio.ch.SourceChannelImpl(在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 个答案:

答案 0 :(得分:6)

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

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