2012-04-06 12 views
7

Ho la possibilità di estendere una classe in fase di compilazione, ma ho bisogno di essere in grado di creare un'istanza di questa sottoclasse in fase di esecuzione utilizzando un'istanza della superclasse già istanziata.Java: estensione della classe al runtime

Ciò dovrebbe essere teoricamente possibile perché i costruttori di superclasse sono già stati chiamati prima del costruttore della sottoclasse.

Non ho accesso al programma in modo sufficiente per modificare l'istanza della mia sottoclasse né per interrompere l'istanziazione originale.

Caso di utilizzo: esiste una matrice esistente di istanze di classe X. Il mio codice viene caricato in dopo. Ho bisogno di sovrascrivere uno dei metodi di una delle istanze X con la mia sottoclasse caricata Y estende X. Il programma principale accede agli oggetti solo attraverso quella matrice, quindi voglio sostituire quell'elemento dell'array con la mia istanza Y, ma ha bisogno di comportarsi come se fosse istanziato originariamente in quell'array. Non posso semplicemente racchiudere l'istanza della superclasse e inoltrare le chiamate, e ci sono complicazioni difficili con il reintegrare la superclasse.

Spero che sia più chiaro.

+3

Si prega di riformulare la domanda. –

+1

Puoi anche fornire un esempio di ciò che stai effettivamente cercando di realizzare? Invece di solo il tuo desiderato, ma possibilmente impossibile, metodo per farlo. – millimoose

+0

Assume la linea esistente "public static Foo foo = new Foo();" che non posso alterare. Ho "public class Bar extends Foo" e voglio fare "foo = new Bar (...)" in modo tale che fosse come se la prima riga fosse "public static Foo foo = new Bar()". – JAKJ

risposta

5

Per ripetere ciò che si sta tentando di fare ..

All'interno della JVM esiste un'istanza di ClassA. Vorresti modificare dinamicamente l'heiarchia di classe di ClassA, in modo tale che esista una nuova classe chiamata ClassB che deriva da ClassA. Quindi si desidera istanziare un'istanza di ClassB, ma la sua implementazione di sottoclasse è quella dell'istanza esistente di ClassA. Qualcosa come una sostituzione di memoria.

Si potrebbe voler esaminare http://www.jboss.org/javassist. Quello che dovresti fare è sostituire il ClassLoader, quindi determinare quando viene caricato ClassA, quindi istanziato. Dovresti quindi costruire ClassB e restituirlo.

Aggiornamento

Dopo un po 'più di ricerca c'è ancora la possibilità che si può fare quello che vuoi. Gli IDE come Eclipse supportano le implementazioni del metodo HotSwap durante il debugging. Usano l'API Instrumentation.

http://zeroturnaround.com/blog/reloading_java_classes_401_hotswap_jrebel/

È possibile sostituire i corpi di metodo, ma non aggiungere o rimuovere i metodi stessi. Pertanto, anche se non sarà possibile modificare il tipo con il nuovo tipo, è possibile sostituire completamente l'implementazione del metodo con la nuova implementazione.

+0

Non sto modificando l'ereditarietà in fase di esecuzione, ma solo istanziando una sottoclasse quando la sua superclasse è già istanziata. – JAKJ

+0

@JAKJ La risposta è sempre la stessa. Hai un oggetto esistente che desideri adattare in un altro tipo di oggetto. Se è possibile controllare il punto di ritorno iniziale di questo nuovo oggetto, è possibile adattarlo e restituire l'istanza desiderata. Ti suggerisco di aggiornare la tua domanda con il tuo caso d'uso, non quello che pensi sia la soluzione. –

+0

Non ho la possibilità di sostituire il classloader poiché la mia classe viene caricata dopo la superclasse, né posso usare runtime di terze parti. Questo deve essere all'interno di Java. – JAKJ

1

Hai guardato i proxy Java?

Ecco un frammento da Javadoc:

"una classe proxy dinamica (semplicemente indicato come una classe proxy di seguito) è una classe che implementa un elenco di interfacce specificate in fase di esecuzione quando viene creata la classe"

+0

Sembra che i proxy siano per le interfacce, non per le classi. – JAKJ

3

Io suggerirei di usare cglib:

cglib è un potente, elevate prestazioni e qualità generazione di codice Biblioteca, che viene usato per estendere le classi Java e implementa le interfacce in fase di esecuzione

È può trovare alcuni esempi qui: https://github.com/cglib/cglib/wiki

2

Non so se è un sollution ma se avete

public static Foo foo = new Foo(); 

e si desidera sostituirlo con Bar, che si estende Foo fare Bar un wrapper per di Foo e l'uso di riflessione per permettere punto foo all'istanza Bar.

public class Foo extends Bar { 
    private bar; 
    public Foo(Bar oldInstance) { 
    this.bar = oldInstance; 
    } 
} 

e

// exception handling ommitted 
public static void onStartup() { 
    Class fooRefClass = FooRef.class; 
    Field fooRef = fooRefClass.getDeclaredField("foo"); 

    Foo foo = (Foo)fooRef.get(null); 
    Bar bar = new Bar(foo); 
    fooRef.set(null, bar); 

}

come detto non so se questo è possibile nel tuo caso.

Problemi correlati