Может ли class Java добавлять метод вовремя?
Может ли class добавить метод к себе во время выполнения (например, из static
блока), чтобы, если кто-то выполняет reflection этого classа, он увидит новый метод, хотя он не был определен во время компиляции?
Задний план:
doAction(...)
которую я использую, предполагает, что classы Action
должны быть определены с doAction(...)
, по соглашению. Структура проверяет эти classы во время выполнения, чтобы узнать, какие типы параметров доступны в их doAction()
. Например: doAction ( String a, Integer b)
- Codesign API Dropbox не работает в Xcode 4.6.3: «Объект кода вообще не подписан»
- Когда можно использовать обработку исключений для бизнес-логики?
- Отключение автоматического форматирования в Visual Studio
- Подписывание ароматов продуктов с gradleиентом
- Генерировать различные случайные числа в C #
Я хотел бы, чтобы каждый class doAction()
возможность программно генерировать свой doAction()
с различными параметрами точно в срок, когда он проверяется. Тело метода может быть пустым.
- Как определить неиспользуемые определения css
- Файлы заголовков C ++, разделение кода
- Не удается получить доступ к родительским элементам при работе с аннотациями макросов
- Что означает == $ 0 (double equals dollar zero) в инструментах разработчика Chrome?
- Завершение кода PHP NetBeans
- В чем разница между собственным кодом, машинным кодом и кодом сборки?
- «CompanyName.Foo» - это «пространство имен», но используется как «тип»,
- Форматирование ReSharper: выравнивание равных операндов
Это не просто. Когда class загружается загрузчиком classов, нет способа изменить методы загруженных classов. Когда class запрашивается, загрузчик classов загрузит его и свяжет . И нет способа (с Java) изменить связанный код или добавить / удалить методы.
Единственный трюк, который приходит мне на ум, это играть с загрузчиками classов. Если мы удалим пользовательский загрузчик classов, classы, загруженные этим загрузчиком classов, должны быть удалены или недоступны. Идея, которая приходит мне на ум, – это
- реализовать один пользовательский загрузчик classов
- загрузить динамический class с помощью этого пользовательского загрузчика classов
- если у нас есть обновленная версия этого classа,
- удалить пользовательский загрузчик classов и
- загрузите новую версию этого 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(); } } }
Затем, используя отражения, вы можете установить или отключить атрибут.