2012-12-08 4 views
11

In Java, è possibile sovrascrivere i metodi in una classe che si crea utilizzando reflection? Ad esempio, dire che ho la seguente classe:Come posso sovrascrivere i metodi in Java quando creo un oggetto tramite riflessione?

public class MyObject 
{ 
    public String foo, bar; 

    public MyObject(String foo) 
    { 
     this.foo = foo; 
     this.bar = foo + "bar"; 
    } 

    public void setBar(String bar) 
    { 
     this.bar = bar; 
    } 
} 

E in una classe voglio creare direttamente e ignorare il suo metodo setBar come segue:

MyObject obj = new MyObject("something") 
{ 
    @Override 
    public void setBar(String bar) 
    { 
     this.bar = this.foo; 
    } 
}; 

Esiste un modo per ignorare un metodo in questo stesso modo usando la riflessione? Forse qualcosa del genere? :

Class<?> _class = Class.forName("com.example.MyObject"); 
Constructor<?> _constructor = _class.getConstructor(new Class<?>[]{String.class}); 
Method m = _class.getMethod("setBar", new Class<?>[]{String.class}); 
Object obj = _constructor.newInstance("Foo String") 
{ 
    m = new Method(new Class<?>[]{String.class}) 
    { 
     System.out.println("Foobar"); 
    } 
}; 

In caso contrario, ci sono altri modi per farlo o una libreria esterna che potrebbe essere d'aiuto? Sto cercando il modo di aggiungere listener ad un metodo setter per cambiare i valori bindati.

+1

È necessaria una libreria di generazione del codice dinamico, ad esempio * javassist *. –

risposta

10

No, non è possibile nel tuo esempio.

Nel tuo esempio, il compilatore Java creerà due classi distinte:

MyObject.class 
MyObject$1.class 

Quest'ultimo è quello con il metodo override. In questo caso, si tratta di una anonima classe interna (Vedi Java tutorial documentation)

Ma c'è una soluzione più complessa che coinvolge le biblioteche bytecode di tessitura. Librerie come cglib, asm, javassist ecc. Ti danno la possibilità di creare dinamicamente nuove classi in fase di runtime e caricarle.

Javassist ha un tutorial su come add methods to classes at runtime. Dovrebbe essere possibile adattarlo per aggiungere/sovrascrivere il metodo, ad esempio:

CtClass origClazz = ClassPool.getDefault().get("org.example.MyObject"); 
CtClass subClass = ClassPool.getDefault().makeClass(cls.getName() + "New", origClazz); 
CtMethod m = CtNewMethod.make(
      "public void setBar(String bar) { this.bar = bar; }", 
      subClass); 
subClass .addMethod(m); 
Class clazz = cc.toClass(); 
+0

Questo è quasi esattamente quello che stavo cercando - ma posso sicuramente adattarlo. Grazie! – Phil

0

No, quello che stai chiedendo è qualcosa come la compilazione di runtime. Anche se non impossibile, certamente non è qualcosa che fornisce l'API di reflection.

2

Se stai tornando un oggetto di un tipo di interfaccia, è possibile utilizzare Proxy.newProxyInstance per ottenere un'istanza di un'interfaccia che trasmette in modo dinamico le chiamate di metodi a un oggetto InvocationHandler cui è possibile scrivere a fare qualsiasi comportamento personalizzato che si desidera.