Как получить байт-код в виде байтового массива из класса

Учитывая произвольный 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 читать в байтах. (не применимо для классов, генерируемых во время выполнения)

Другие вопросы по тегам