Может ли class Java добавлять метод вовремя?

Может ли class добавить метод к себе во время выполнения (например, из static блока), чтобы, если кто-то выполняет reflection этого classа, он увидит новый метод, хотя он не был определен во время компиляции?

Задний план:

doAction(...) которую я использую, предполагает, что classы Action должны быть определены с doAction(...) , по соглашению. Структура проверяет эти classы во время выполнения, чтобы узнать, какие типы параметров доступны в их doAction() . Например: doAction ( String a, Integer b)

Я хотел бы, чтобы каждый class doAction() возможность программно генерировать свой doAction() с различными параметрами точно в срок, когда он проверяется. Тело метода может быть пустым.

Это не просто. Когда class загружается загрузчиком classов, нет способа изменить методы загруженных classов. Когда class запрашивается, загрузчик classов загрузит его и свяжет . И нет способа (с Java) изменить связанный код или добавить / удалить методы.

Единственный трюк, который приходит мне на ум, это играть с загрузчиками classов. Если мы удалим пользовательский загрузчик classов, classы, загруженные этим загрузчиком classов, должны быть удалены или недоступны. Идея, которая приходит мне на ум, – это

  1. реализовать один пользовательский загрузчик classов
  2. загрузить динамический class с помощью этого пользовательского загрузчика classов
  3. если у нас есть обновленная версия этого classа,
  4. удалить пользовательский загрузчик classов и
  5. загрузите новую версию этого classа с помощью нового экземпляра пользовательского загрузчика classов

Я оставляю это как пищу для размышлений , не могу доказать, если это приведет к решению или если у нас есть подводные камни.

В качестве простого ответа на вопрос: Нет, мы не можем изменить загруженный class, так как мы можем изменить содержание полей с reflectionм. (мы не можем добавлять или удалять поля тоже).

Andres_D прав, мы можем очень хорошо это сделать, используя пользовательскую загрузку classов, вот подробное руководство о том, как это сделать: http://www.javaworld.com/javaworld/jw-06-2006/jw-0612-dynamic. HTML? страница = 1

В статье объясняется, как написать динамический Java-код. В нем обсуждается компиляция исходного кода выполнения, перезагрузка classов и использование шаблона проектирования прокси, чтобы внести изменения в динамический class, прозрачный для его вызывающего.

Фактически исследователь в Австрии написал JVM, который даже позволяет перезагружать classы с разными иерархиями типов. Они достигли этого, используя существующие точки сохранения streamа, чтобы генерировать полную «боковую вseleniumную» объекта и все связанные с ним ссылки и ссылки на контент, а затем после полного перетаскивания со всеми необходимыми изменениями просто заменяют все измененные classы. [1] Здесь ссылка на их проект http://ssw.jku.at/dcevm/ спонсорство oracleа, безусловно, вызывает интересные размышления о будущих планах.

Менее интрузивные изменения в телах и полях методов уже возможны в стандартной виртуальной машине Java с использованием возможностей «горячей замены» JPDA, как это было представлено в Java 1.4:
docs.oracle.com/javase/1.4.2/docs/guide/jpda/enhancements.html#hotswap

Я не уверен, был ли он первым, но этот документ сотрудника Sun от 2001 года, по-видимому, является одним из ранних предложений, в которых упоминаются возможности HotSpot для «горячей замены». [2]

СПРАВКА

[1] T. Würthinger, C. Wimmer и L. Stadler, «Динамическая эволюция кода для Java», представленные на 8-й Международной конференции по принципам и практике программирования на Java, Вена, 2010.

[2] М. Дмитриев, «На пути к гибкой и безопасной технологии эволюции приложений Java-приложений во время выполнения», в семинаре OOPSLA по инженерно-комплексным объектно-ориентированным системам эволюции, 2001.

Я никогда не пробовал ничего подобного, но вы должны взглянуть на ASM , cglib и Javassist .

Нет, это невозможно (легко) на Java.

Похоже, вы пытаетесь использовать Java, как если бы это был язык динамического программирования. Например, у Ruby есть открытые classы: вы можете добавлять и удалять методы из classов Ruby во время выполнения. В Ruby вы также можете использовать метод «method missing» в своем classе, который вызывается при попытке вызвать метод, который не существует в classе. Такая вещь также не существует на Java.

Существует версия Ruby, которая работает на JVM, JRuby, и ей приходится делать очень сложные трюки, чтобы заставить открытые classы работать в JVM.

У вас может быть метод doAction который делает все, что вы хотите, чтобы сгенерированный метод выполнял. Есть ли причина, по которой она должна быть создана или может быть динамичной?

Я считаю, что вам нужен какой-то байт-код, изменяющий инструмент / фреймворк, такой как asm, cglib или javassist. Вы можете достичь этого с помощью аспектов / ткачества, как это сделано весной, но я считаю, что вам все еще нужно сначала определить метод.

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

То, что я предлагаю, должно работать для вашей ситуации: 1. У вас есть существующий class MyClass с n методами 2. Вы хотите включить (n + 1) -й метод, который не находится в classе при компиляции в другом исходном файле .java

Мой способ решить это Наследование. Создайте новый исходный файл .java для classа MyClassPlusOne, расширяющего первый class MyClass. Скомпилируйте этот class и используйте этот объект. Как я могу скомпилировать и развернуть class java во время выполнения?

 class MyClassPlusOne extends MyClass { void doAction(String a, Integer b) { int myNPlus1 = a+b; //add whatever you want before compiling this code } } 

Я не уверен, что это возможно. Однако вы можете использовать AspectJ, ASM и т. Д. И переплетать эти методы в соответствующие classы.

Другой альтернативой является использование композиции для обертывания целевого classа и предоставления метода doAction. В этом случае вы должны делегировать целевой class.

Похоже, нет возможности динамически добавлять метод. Но вы можете подготовить class со списком методов или хешей вроде:

 import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.HashMap; public class GenericClass { private HashMap methodMap = new HashMap(); public Object call(String methodName,Object ...args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { Method method = methodMap.get(methodName); return method.invoke(null, args); } public void add(String name,Method method){ if(Modifier.isStatic(method.getModifiers())) methodMap.put(name, method); } public static void main(String[] args) { try { GenericClass task = new GenericClass(); task.add("Name",Object.class.getMethod("Name", new Class[0])); } catch (NoSuchMethodException | SecurityException e) { e.printStackTrace(); } } } 

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

  • Как испускать и выполнять байт-код Java во время выполнения?
  • Как получить «кодовое обозначение» gdb на OSX?
  • Форматирование Литеральные параметры fragmentа кода C #
  • Код C ++ в файлах заголовков
  • Отладчик Visual Studio - отображение целочисленных значений в шестнадцатеричном виде
  • Как я могу тестировать графический интерфейс?
  • Покрытие кода, не показывающее результаты с помощью Xcode + gcov
  • Можете ли вы создавать представления sql / хранимую процедуру с использованием Entity Framework 4.1 Первый подход к коду
  • Проверка указателя NULL в C / C ++
  • «Взаимодействие с пользователем не разрешено», пытаясь подписать приложение OSX с использованием кода
  • Когда использовать утверждение и когда использовать исключение
  • Давайте будем гением компьютера.