2009-06-28 7 views
25

Es ist in plain Java möglich, eine Methode einer Klasse programmgesteuert zur Laufzeit zu überschreiben (oder sogar eine neue Methode zu erstellen)?Java-Reflektion: Wie überschreibe oder generiere ich Methoden zur Laufzeit?

Ich möchte in der Lage sein, dies zu tun, auch wenn ich nicht kennen die Klassen zur Kompilierzeit.

Was ich genau damit meine zur Laufzeit überschrieben:

abstract class MyClass{ 
    public void myMethod(); 
} 

class Overrider extends MyClass{ 
    @Override 
    public void myMethod(){} 
} 

class Injector{ 
    public static void myMethod(){ // STATIC !!! 
    // do actual stuff 
    } 
} 

// some magic code goes here 
Overrider altered = doMagic(
    MyClass.class, Overrider.class, Injector.class); 

Nun, diese Aufruf ...

altered.myMethod(); 

... nennen würde Injector.myMethod() statt Stoßstangen .myMethod().

Injector.myMethod() ist statische, weil nach der „Magie“ zu tun es aus verschiedenen Klasseninstanz aufgerufen wird (es ist die Stoßstangen), (so verhindern wir es den Zugriff auf lokale Felder).

+1

Können Sie uns sagen, welche Art von Objekten Sie überschreiben möchten? Auf den zweiten Blick erinnert mich Ihr Problem an das Ziel des Abhängigkeits-Injektionsparadigmas. – akarnokd

Antwort

10

Sie können zur Erzeugung von Code so etwas wie cglib verwenden

8

Für Schnittstellen gibt es java.lang.reflect.Proxy.

Für Klassen benötigen Sie entweder eine Bibliothek eines Drittanbieters oder schreiben ein wenig Code. Das generelle dynamische Erstellen von Klassen auf diese Weise besteht darin, Mocks zum Testen zu erstellen.

Es gibt auch die Instrumentierungs-API, mit der Klassen geändert werden können. Sie können Klassen auch mit einem benutzerdefinierten Klassenlader oder nur mit den Klassendateien auf der Festplatte ändern.

+0

@ T.H.t: Würde AOP- oder BCEL-Style-Re-Engineering Ihrer Meinung nach auch in diesem Fall anwendbar sein?Ich bin derzeit mit einem ähnlichen Problem konfrontiert und kann nicht entscheiden, was zu verwenden ist. – akarnokd

+1

AOP ist sehr allgemein. Ich bevorzuge ASM zu BCEL. oxbow_lakes erwähnt cglib, woran ich mich nicht erinnern konnte (und nicht benutzt habe). –

0

on-the-fly Wenn ich es bekam, rechts das Hauptproblem, das Sie betrifft, wie eine statische Methode delegieren passieren (wie in C#), durch die Instanzschnittstellenmethode.

Sie können diesen Artikel überprüfen: A Java Programmer Looks at C# Delegates, die Ihnen zeigt, wie Sie einen Verweis auf Ihre statische Methode abrufen und aufrufen. Sie können dann eine Wrapper-Klasse erstellen, die den Namen der statischen Methode in ihrem Konstruktor akzeptiert, und Ihre Basisklasse implementiert, um die statische Methode von der Instanzmethode aus aufzurufen.

8

Ich schrieb eine article for java.net darüber, wie Sie Logging-Anweisungen transparent zu einer Klasse hinzufügen, wenn es vom Klassenlader mit einem Java-Agent geladen wird.

Es verwendet die Bibliothek Javassist den Bytecode zu manipulieren, die Javassist Compiler einschließlich der Verwendung von zusätzlichen Bytecode zu erzeugen, die dann an der entsprechenden Stelle eingelegt wird, und dann wird die sich ergebende Klasse der Klassenladeprogramm vorgesehen ist.

Eine verfeinerte Version ist mit dem Projekt slf4j verfügbar.

+0

Jetzt einige Jahre später, werde ich diesen Ansatz nicht empfehlen. Wenn Sie dies wirklich brauchen, sehen Sie sich die Aspektorientierte Programmierung an. –

9

In java6 wurde die Möglichkeit hinzugefügt, jede bereits geladene Klasse zu transformieren. Werfen Sie einen Blick auf die changes in der java.lang.instrument Paket

+0

Ich habe sogar vergessen, dass dieses Paket existiert! Vielen Dank! –

Verwandte Themen