代码之家  ›  专栏  ›  技术社区  ›  L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳

为什么会这样Class.getPackage 为不同包中的类返回相同的包?

  •  6
  • L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳  · 技术社区  · 15 年前

    我做了一个新的 ClassLoader Class Class.getPackage getPackage 在我的主命名空间中的任何其他类上。

    根据 JVM spec :

    接口由包决定 类加载器的名称和定义 类或接口。

    换句话说,如果在同一个包中有两个类,但是由不同的类加载器加载,那么它们被认为在不同的包中(这也可以通过下面我的测试用例中的反射来“确认”。)

    所以当我这么做的时候,我得到的结果是一样的 获取包 在两个班上?

    package pkg;
    import java.io.*;
    
    // Yes, you can try commenting this class, you'll get the same result.
    class LoadedClass {
        LoadedClass() {
            System.out.println("LoadedClass init");
        }
    }
    
    class MyClassLoader extends ClassLoader {
        Class<?> defineClass(String name, byte[] b) {
            return defineClass(name, b, 0, b.length);
        }
    }
    
    class Main {
        public static void main(String[] args) throws Exception {
            MyClassLoader mcl = new MyClassLoader();
    
            // load compiled class from file
            FileInputStream fileinputstream = new FileInputStream(
                "/home/me/test/pkg/LoadedClass.class" /* <- point to whever these classes
                                                       *    are being compiled to. */
            );
            int numberBytes = fileinputstream.available();
            byte classBytes[] = new byte[numberBytes];
            fileinputstream.read(classBytes);
            fileinputstream.close();
    
            Class<?> lc = mcl.defineClass("pkg.LoadedClass", classBytes);
            Package myPackage = Main.class.getPackage();
            Package lcPackage = lc.getPackage();
            System.out.println("lc package: " + lcPackage);
            System.out.println("my package: " + myPackage);
            System.out.println("lc ClassLoader: " + lc.getClassLoader());
            System.out.println("lc ClassLoader parent: " +
                               lc.getClassLoader().getParent());
            System.out.println("my ClassLoader: " + Main.class.getClassLoader());
            System.out.println("are they equal? " + (lcPackage == myPackage));
            if (lcPackage == myPackage) {
                System.out.println("okay... we should be able to instantiate " +
                                   "the package if that's true, lets try");
                lc.newInstance(); // boom as expected
            }
        }
    }
    

    它输出:

    lc package: package pkg
    my package: package pkg
    lc ClassLoader: pkg.MyClassLoader@7987aeca
    lc ClassLoader parent: sun.misc.Launcher$AppClassLoader@1f7182c1
    my ClassLoader: sun.misc.Launcher$AppClassLoader@1f7182c1
    are they equal? true
    okay... we should be able to instantiate the package if that's true, lets try
    Exception in thread "main" java.lang.IllegalAccessException: Class pkg.Main can not access a member of class pkg.LoadedClass with modifiers ""
        at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:65)
        at java.lang.Class.newInstance0(Class.java:349)
        at java.lang.Class.newInstance(Class.java:308)
        at pkg.Main.main(Main.java:42)
    

    不同的 包(相同的名称,不同的命名空间),这是正确的AFAIK,因为它强制类型安全。

    我只是想知道,因为我在过去几天一直在研究JVM和安全体系结构,并不断发现像这样的细微之处,所以很难推理。

    1 回复  |  直到 15 年前
        1
  •  5
  •   Stephen C    15 年前

    这个 getPackage 方法未指定。这是什么 bug 4256589

    ClassLoader.getPackage(“foo”)返回为包定义的包对象 如果这个类加载器没有定义 包foo时,该方法返回父类装入器为其定义的内容 福,如果有的话。

    Package 返回的对象 获取包 取决于类加载器是“定义”了类包本身,还是在其父类加载器中找到了该包。我们看到的行为似乎与此一致。

    这是相当不一致的。但是有一个包对象还是有多个包对象真的有区别吗?当然,它不应该有任何区别的类型安全或安全。。。除非您在自定义类加载器或安全管理器中实现了一些特殊的基于包的安全方案。