2015-05-29 2 views
0

Я задавался вопросом, что делать, если у меня есть следующий случай:Как генерировать методы динамически в Java

public class MyObject<T> { 
    private T myTObject; 

    public void setMyTObject(T m) { 
     myTObject = m; 
    } 

    public T getMyTObject() { 
     return myTObject; 
    } 
} 

А теперь я хочу, чтобы класс реагировать что-то вроде этих:

MyObject<ObjectA> objA = new MyObject<ObjectA>(); 
ObjectA objAInstance = objA.getObjectA(); 

или

objA.setObjectA(otherObjectAInstance); 

Есть ли способ динамически создавать методы, основанные на имени класса Т? Или мне лучше расширить ObjectA до MyObject и создать эти методы с помощью super.get/seMyObject()?

Для уточнения:

Идея заключается в том, чтобы иметь геттер и сеттер метод генерируется динамически так, если я создаю экземпляр:

MyObject<A> objA = new MyObject<A>(); 

Я мог бы вызвать метод:

objA.getA(); 

Гета() будем называть внутренне getMyTObject() или просто вернуть myTObject

поэтому MyObject может реагировать на основе класса T и генерировать соответствующий метод.

У меня обновлен атрибут элемента, чтобы отличать класс MyObject, это может привести к путанице. также фиксированный возврат метода и тип параметра.

+0

Ну, можно [генерировать классы и методы «на лету» с генераторами байтового кода] (https://commons.apache.org/proper/commons-bcel/manual.html), но это непросто. Существует также класс [Прокси] (http://docs.oracle.com/javase/7/docs/api/java/lang/reflect/Proxy.html), который использует отражение. Но в целом вам лучше использовать расширение, если сможете. – markspace

+0

Я думаю, что это случай смотреть на отражение в java .. –

+0

Я ничего не читаю о том, почему вы хотите это сделать? Только потому, что вы можете или есть единственная причина, по которой вы найдете более подходящее соглашение об именах для ваших геттеров и сеттеров, чтобы зависеть от фактического общего типа? В последнем случае просто забывайте об этом, никто этого не делает, это не стоит, просто используйте общие имена для ваших геттеров и сеттеров, и все в порядке. Нет никакой пользы, вся современная IDE расскажет вам о возвращаемых и заданных типах конкретных объектов. Посмотрите стандартный Java API и общие классы, такие как List , Map и т. Д. –

ответ

0

Обновление Ответ полностью изменен.

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

Вместо этого, это возможное решение с использованием дженериков. Обратите внимание, что это что-то вроде быстрого и грязного взлома; Я оставляю его для уточнения. Вы определяете интерфейс с добытчиками и сеттеров, которые вы хотите, с тем, что вы хотите их именем:

package com.example.dcsohl; 

public interface IntegerWrapper { 

    public Integer getInteger(); 
    public void setInteger(Integer i); 

} 

А затем, чтобы использовать их, вы использовать этот класс, чтобы делать тяжелую работу. Обратите внимание, что проверка ошибок не очень хороша; например, он не проверяет, что «getFoo» вообще соответствует имени передаваемого класса; и не подтверждает, что «foo» в «getFoo» соответствует методу «setFoo». Это то, что вы можете улучшить.

package com.example.dcsohl; 

import java.lang.reflect.InvocationHandler; 
import java.lang.reflect.Method; 
import java.lang.reflect.Proxy; 

public class ProxyWrapper<T> implements InvocationHandler { 

    Class<T> clazz = null; 
    T myvalue = null; 

    public static <W,T> W getInstance(Class<W> clazz, Class<T> clazz2) { 
     ProxyWrapper<T> wrapper = new ProxyWrapper<T>(); 
     wrapper.setClass(clazz2); 
     @SuppressWarnings("unchecked") 
     W proxy = (W)Proxy.newProxyInstance(clazz.getClassLoader(), new Class[] {clazz}, wrapper); 
     return proxy; 
    } 

    private void setClass(Class<T> clazz) { 
     this.clazz = clazz; 
    } 

    public Object invoke(Object proxy, Method method, Object[] args) 
      throws Throwable { 
     // getter has no arguments 
     if (method.getName().startsWith("get") && (args == null || args.length == 0)) { 
      return myvalue; 
     } else if (method.getName().startsWith("set") && args.length == 1) { 
      Object o = args[0]; 
      if (o.getClass().isAssignableFrom(clazz)) { 
       @SuppressWarnings("unchecked") 
       T val = (T)o; 
       myvalue = val; 
       return null; 
      } 
     } else { 
      throw new Exception(); 
     } 
     return null; 
    } 


} 

Наконец, чтобы использовать его, вот краткий пример:

package com.example.dcsohl; 

public class Main { 

    public static void main(String[] args) { 

     Integer foo = 5; 

     IntegerWrapper wrapper = ProxyWrapper.getInstance(IntegerWrapper.class, Integer.class); 
     wrapper.setInteger(foo); 

     Integer bar = wrapper.getInteger(); 
     System.out.println(bar); 
    } 

} 

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

+0

Это не отвечает на его вопрос, насколько я понимаю. Он хочет, чтобы имя самого метода было 'getObjectA()' вместо 'getT()' или 'getMyObject()'. – NoseKnowsAll

+0

Охх. Вы правы, я забыл об этом. Слишком сфокусирован на сигнатуре метода и не столько на имени. – dcsohl

+0

Извините, я неправильно написал имена методов, я исправил вопрос, соответственно, NoseKnowsAll получил эту идею. В конце я хочу избежать создания кучи классов, которые распространяются на MyObject , который реализует только метод getTObject()/setTObject (T arg) –

Смежные вопросы