Доступ к частным переменным пакета с использованием зарезервированного имени пакета

Я изучал исходный код java.util.HashMap, и я хотел посмотреть, насколько хорошо функция хэш-кода распределяет ключи во внутреннем массиве Entry (который является закрытой переменной пакета ). Поэтому я сделал пакет с именем java.util в своем проекте только для того, чтобы проверить, могу ли я обмануть компилятор, заставив его думать, что это тот же пакет. Удивительно, но это сработало, и я написал следующий код:

package java.util;

public class HashMapExt<K, V> extends HashMap<K, V> implements Map<K, V> {

    public static void main(String[] args) {
        HashMapExt<Integer, String> mp = new HashMapExt<Integer, String>();
        mp.put(1, "Hello");
        mp.put(2, "Map");
        mp.put(3, "Extention");
        mp.printData();
    }

    void printData() {

        System.out.println(Arrays.toString(table));
    }
}

Он успешно скомпилирован, но при запуске выдал исключение:

Exception in thread "main" java.lang.SecurityException: Prohibited package name: java.util
    at java.lang.ClassLoader.preDefineClass(Unknown Source)
    at java.lang.ClassLoader.defineClass(Unknown Source)
    at java.security.SecureClassLoader.defineClass(Unknown Source)
    at java.net.URLClassLoader.defineClass(Unknown Source)
    at java.net.URLClassLoader.access$000(Unknown Source)
    at java.net.URLClassLoader$1.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at java.lang.ClassLoader.loadClassInternal(Unknown Source)

Теперь вопрос в том, можно ли изменить модель безопасности по умолчанию, чтобы я мог получить доступ к внутренней переменной table, или есть какая-либо другая альтернатива (возможно, с использованием отражения)?


person Emil    schedule 19.11.2010    source источник


Ответы (2)


Даже если есть возможность разместить ваш класс в пакете java.util (например, заменить основной jar или определить собственный загрузчик классов), вам лучше использовать отражение. Это просто и понятно:

Field tableField = HashMap.class.getDeclaredField("table");
tableField.setAccessible(true);
Map.Entry[] entries = (Map.Entry[]) tableField.get(yourMap);
person Bozho    schedule 19.11.2010

Вы можете попробовать либо добавить свою банку в путь к классам, либо использовать одобренный каталог.

Первый:

java -Xbootclasspath/p:youJarHere.jar  ..... 

И эффект заключается в том, чтобы сначала загрузить классы, которые у вас есть в вашем Jar, даже переопределяя основные классы.

Более поздняя форма заключается в размещении в вашем каталоге $JAVA_HOME/lib/endorsed классов/jars, это имеет аналогичный эффект.

Я не использовал ни один из них в течение нескольких лет, но однажды я использовал их для замены основного класса (что-то в пакете CORBA или что-то в этом роде).

Попробуйте и дайте нам знать, если это сработало.

Вот несколько ссылок:

http://blogs.sourceallies.com/2010/02/replacing-and-patching-java-application-and-core-classes/

http://download.oracle.com/javase/6/docs/technotes/guides/standards/

person OscarRyz    schedule 19.11.2010
comment
Это немного сбивает с толку. Что такое одобренный каталог? - person Emil; 19.11.2010
comment
Из ссылки: Механизм переопределения утвержденных стандартов предоставляет средства, с помощью которых более поздние версии классов и интерфейсов, реализующих одобренные стандарты или автономные технологии, могут быть включены в платформу Java. Похоже, что java.util не подходит для этого. механизм однако. я обновлю ответ - person OscarRyz; 19.11.2010