DioD
offline
Опыт:
45,184Активность: |
Java от RawCode: Сбрасываем шкурки: sun.reflect
Перед основным текстом, я хочу чтобы Вы прочитали замечательную цитату:
она ответит на все ваши вопросы касательно причин появления и смысла этой статьи. Исходные коды можно читать где угодно, я использую:
а) Читая исходные тексты некоторых классов которые идут в комплекте, например Class, Runtime, Object и куча других, вы можете обратить внимание на методы, которые объявлены native и не имеют никакого кода....
Эти методы написаны на другом языке и выполняются вне JVM, с исходным кодом этих методов можно ознакомится скачав сорцы hotspot или сорцы сторонней библиотеки, если они конечно есть. Ваши собственные классы тоже могут вызывать нативный код, этот функционал называется JNI и позволяет делать, что угодно, но только для определённой платформы (или компилировать для всех платформ разом). Нативные классы не имеют никаких особых указателей, вместо этого они имеют пустой приватный конструктор, при нормальном функционировании инстансы этих классов создаёт сама виртуальная машина, при этом никаких ограничений нет, вплоть до того, что может быть создан класс, который стандартными методами создать не возможно в принципе.
Например инстанс класса Class создать можно только через Unsafe, даже со всеми привелегиями, вам не дадут это сделать стандартными методами. Некоторые классы которые создаёт виртуальная машина имеют дополнительные поля, которые кроме как через Unsafe не прочитать и не записать, их даже в списке не будет, но они есть.
Статичные поля являются свойством класса, "просто" поля являются свойством отдельного объекта, но в любом случае вам потребуется получить инстанс класса для работы.
А) Все объекты являются наследником класса Object (даже если это не написано) который имеет финальный нативный метод getClass(), который позволяет выжать из объекта инстанс класса, который этот объект описывает, на любых объектах без исключений, массивы тоже считаются объектами, но с ними всё чуточку не так.
System.out.println(Class.class.getSuperclass()); Б) Если вы знаете полное имя класса, но у вас нет объекта, вы можете получить инстанс класса методом forName(String). В) Если вы не знаете полное имя класса, но знаете каким класлоадером он загружен, можно пробежатся по полю "classes" этого класслоадера, указанное поле содержит указатели на все классы, которые были загружены. С) Если никаких зацепок нет - ищите лучше, безопасного поиска по хипу мне не известно, а небезопасный роняет виртуальную машину, совсем, никаких вам эксепшинов.
Однако при большом желании можно изменить данные кеша и удержать указатель на модифицированный массив (чтобы его не съел сборщик мусора), в этом случае можно будет обмануть стандарную рефлекцию или выдать не те результаты, что ожидает программа. Так как все эти поля добавлены в фильтр, получить указатель на них без Unsafe нельзя, так что пример будет ниже.
В случае с методами и полями, вы не получите указатель на поле или метод в принципе
Часть объектов которые находятся в этих самых полях имеют особую структуру не соответствующую декларации ни одного из существующих классов, так что даже если и получить на них указатель, сделать с ними по большей части ничего нельзя, а если их "изменить" то последствия могут быть достаточно весёлые.
Например если сломать объект который хранит блокировки потока, эффект может быть неожиданным:
218 volatile Object parkBlocker; Еще есть весёлые объекты по разным классам которые лучше не трогать, если нет точных сведений о том что они делают и как.
Собственно на этой стадии и начинается "волшебство":
Код достаточно запутанный, с кучей проверок, которые в принципе не интересны, создание получателя поля есть только в одном месте:
Указанный метод после еще пары проверок безопасности выходит на UnsafeFieldAccessorFactory.newFieldAccessor, который в свою очередь выходит на 100500 специализированных классов которые позволяют доставать четыре типа полей на каждый из 9 типов данных (итого 36 разных классов):
А) Static
Б) Volatile В) Volatile Static Г) Normal Самый низкий уровень доступа на данной стадии выглядит вот так:
Как вы видите на этой стадии рефлексия выходит на уровень "Unsafe".
На этом уровне нет ни проверок безопасности ни эксепшинов, неправильные действия могут привести к эксепшину виртуальной машины или сразу уронить виртуальную машину целиком (будет бидабида если на этой же виртуальной машине идёт что-то другое), например если вы попытаетесь прочитать память по отрицательному индексу или сделать какую либо другую глупость (гадость).
Вот мы и дошли до финального уровня, а хотя нет, мы ведь еще не смотрели сорцы JVM!
Я ведь упоминал ранее что единственное значимое поле в объекте Field это слот, вот смотрите как hotspot JVM резолвит объект Field в указатель на место хранения, при этом не существует каких либо проверок безопасности, виртуальная машина смотрит валидность данных в объекте (только валидность, а не то что данные залепа), смотрит кому принадлежит поле (классу или объекту) и выдаёт оффсет для этого поля.
О том как использовать Unsafe будет рассказано отдельно. Отредактировано DioD, 15.12.2013 в 12:56. |
14.12.2013, 19:24 | #1
+0/−0
Профиль |
Приват |
Поиск |
IP: Записан
|