Как получить байт-код в виде байтового массива из класса
Учитывая произвольный Class
экземпляр, в том числе тот, который генерируется во время выполнения (нет .class
файл на диске), есть ли способ получить байты класса?
2 ответа
В общем, это невозможно. При загрузке класса JVM анализирует его байт-код и преобразует его во внутреннее представление. После этого JVM может забыть оригинальный байт-код, и это действительно происходит с HotSpot JVM.
Тем не менее, с помощью определенных хаков можно проверить внутреннее представление класса и преобразовать его обратно в допустимый файл класса (хотя он будет отличаться от исходного байт-кода). Такой процесс используется в HotSpot JVM для воссоздания файла класса в целях инструментирования.
В качестве подтверждения концепции я написал программу, которая извлекает обработанный байт-код загруженного класса из памяти JVM, используя Unsafe
, Это только для демонстрации; никогда не пробуй это в производстве.
РЕДАКТИРОВАТЬ
Вы также можете получить данные файла класса (возможно, модифицированные JVM) с помощью Instrumentation API. Для этого требуется, чтобы агент Java загружался либо при загрузке виртуальной машины (используя -javaagent
Опция VM) или во время выполнения через механизм Dynamic Attach.
Вот пример такого агента: GetBytecode.java.
Наконец, если вы не возражаете против использования нативного кода, есть функции JVMTI GetConstantPool и GetBytecodes для получения байт-кодов конкретного метода Java.
Вот пример JVMTI.
String classFile = "/" + Object.class.getName().replace('.', '/') + ".class";
System.out.println(classFile);
URL url = Test.class.getResource(classFile);
System.out.println(url);
производит этот вывод.
/java/lang/Object.class
jar:file:/usr/java/jdk1.8.0_60/jre/lib/rt.jar!/java/lang/Object.class
так что вы можете использовать url
читать в байтах. (не применимо для классов, генерируемых во время выполнения)