Почему Class.getPackage возвращает тот же Пакет для классов от различных пакетов?

Я делаю новое ClassLoader и заставьте его определить новое Class, что означает, что новый класс должен быть в новом пространстве имен, которое это, AFAIK. Странная вещь, когда я звоню Class.getPackage на новом классе это возвращает тот же самый объект, как возвращено путем вызова getPackage на любом другом классе в моем основном пространстве имен.

Согласно спецификации JVM:

Пакет во время выполнения класса или интерфейса определяется именем пакета и загрузчиком класса определения класса или интерфейса.

Так, другими словами, если Вы имеете два класса в том же пакете, но загружаетесь другим classloaders, они считаются в различных пакетах. (Это может также быть "подтверждено" через отражение в моем тестовом сценарии ниже.)

Так howcome, когда я делаю это, я получаю тот же результат getPackage на обоих классах?

Вот мой тест:

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 и архитектуру безопасности последние несколько дней и продолжаю находить мало тонкости как это так, трудно рассуждать о.

6
задан L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳ 11 August 2010 в 04:22
поделиться