Определение класса во время работы Java-приложения

Можно ли в Java создать определение класса на лету во время работы приложения, а затем создать объект этого класса?

Например, работающее приложение будет считывать текстовый файл, содержащий список членов класса, которые необходимо включить в новый класс. Затем приложение определяло бы определение класса на основе списка членов, а затем создавало бы его.


person Lehane    schedule 23.04.2009    source источник
comment
Так начинается SkyNet.   -  person TheTXI    schedule 23.04.2009
comment
Если бы SkyNet был написан на Java, ему потребовалось бы слишком много памяти, чтобы когда-либо представлять угрозу.   -  person Pesto    schedule 23.04.2009
comment
SkyNet просто построит себе более крупный кластер для работы. Тот факт, что он написан на Java, имеет смысл, поскольку и SkyNet, и Java в конечном итоге станут концом человечества.   -  person TheTXI    schedule 23.04.2009
comment
Я всегда считал, что SkyNet должен быть написан на Perl. Тогда все, что ему нужно будет сделать для развития, это вывести случайные знаки препинания и передать их интерпретатору Perl.   -  person Pesto    schedule 23.04.2009
comment
Просто из любопытства, что вы пытаетесь решить с помощью этого метода? Или вопрос академический?   -  person James McMahon    schedule 23.04.2009
comment
@nemo: В основном из любопытства. Я пишу Java-программу, которая будет выводить определение класса Java, мне, вероятно, не нужно будет создавать объект класса на лету, но я подумал, что было бы здорово сделать это...   -  person Lehane    schedule 25.04.2009


Ответы (11)


Да, теоретически это возможно, ваш файл класса представляет собой байтовый код, который в конце представляет собой массив байтов! затем вы можете использовать метод defineClass(String, byte[], int, int), чтобы получить экземпляр класса, который можно использовать для создания экземпляров объектов посредством отражения.

На практике вы можете использовать что-то вроде CGLib или javaassist.

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

person MahdeTo    schedule 23.04.2009

Вы можете динамически создавать классы с помощью ASM.

person Boune    schedule 23.04.2009

Вы можете сделать это, записав код для вашего нового класса в файл, затем вызвав компилятор Java для этого файла и используя загрузчик классов для динамической загрузки этого класса в работающее приложение. Apache Tomcat делает это для своих страниц JSP; он берет код, вносит в него некоторые изменения, заключает его в блок try/catch в середине класса, который затем записывает в файловую систему, компилирует его и использует загрузчик классов, чтобы получить его и подать в суд на обслуживание запросов.

person Eli Courtwright    schedule 23.04.2009

Конечно, это возможно. См., например, эту статью.

person kgiannakakis    schedule 23.04.2009

Я полагаю, что ASM — это библиотека байт-кода самого низкого уровня для Java. Это делает его очень сложным, но и очень мощным. Я рекомендую прочитать документацию ASM (PDF), чтобы действительно понять, как генерация байт-кода на Яве работает. В этой документации также объясняется, как загрузить байт-код в загрузчик классов (еще одна сложная тема, которую нужно сделать правильно).

После этого вы можете использовать одну из библиотек более высокого уровня, если это облегчит вам жизнь, и понять, что они делают. Во многих случаях, например при создании прокси, CGLIB полезен и прост в использовании. Для большей мощности многие упомянули Javassist (я не я не использовал его - CGLIB и ASM были хороши для меня).

person Esko Luontola    schedule 23.04.2009

Возможно, самым простым решением (с точки зрения отсутствия дополнительных библиотек) будет использование API компилятора Java, поставляемый с Java 6. Вы просто сможете сгенерировать .java, скомпилировать и затем выполнить Class.forName().

person Brian Agnew    schedule 23.04.2009

Возможно, это немного излишне, но Apache BCEL (библиотека разработки байт-кода) может использоваться для создания class файлов. во время выполнения.

Хотя я сам не пробовал, возможно, затем можно было бы создать класс, загрузить его и создать экземпляр во время выполнения.

person coobird    schedule 23.04.2009

Да, это возможно.

Вы можете создавать классы с помощью Javassist во время выполнения, определяя тело класса и заставить javassist скомпилировать ваш новый класс.

Javassist имеет собственный компилятор, который создает байт-код на основе определения вашего класса. У него есть некоторые особые способы обработки вещей, но использовать эту библиотеку очень просто и интуитивно понятно.

Javassist используется на JBoss, и я думаю, что это хорошая ссылка :)

То же самое можно сделать с помощью BCEL, однако это намного сложнее (но таким образом у вас будет больше контроля над тем, что генерируется).

person Edison Gustavo Muenz    schedule 23.04.2009

Вероятно, вы могли бы сделать что-то подобное с JRuby, JPython или Groovy, если нужно.

Если вы чувствуете себя особенно мазохисткой, вы можете посмотреть на BCEL.

person Evan    schedule 23.04.2009

Если вам нужны Java и метапрограммирование, используйте Groovy.

person Stefan Kendall    schedule 23.04.2009
comment
Привет, Стефан, значит, Groovy может помочь скомпилировать во время выполнения класс Java на лету и создать его экземпляр? Есть ли у вас какие-либо указания о том, как это сделать? - person Sergio; 22.09.2013

Здесь был недавний вопрос относительно компиляция в памяти, которая должна дать вам некоторые подсказки о том, что делать после того, как вам удалось сгенерировать исходный код.

person Phil M    schedule 23.04.2009