Java: Wie kann ich das überschreiben einer Methode von einer Klasse dynamisch (Klasse ist schließlich NICHT im classpath)?
Wie rufe ich eine Methode einer Klasse dynamisch + bedingt?
(Klasse ist schließlich nicht im classpath)
Sagen wir mal, ich muss die Klasse NimbusLookAndFeel
, aber auf einigen Systemen ist es nicht verfügbar (D. H. OpenJDK-6
).
Also ich muss in der Lage sein:
- Um es kennen zu lernen, die Klasse ist verfügbar (zur Laufzeit),
- Wenn es nicht der Fall ist, überspringen die ganze Sache.
- Wie komme ich zu überschreiben einer Methode von einem dynamisch geladenen Klasse
(so erstellen Sie eine anonyme innere sub-Klasse)?
Code-Beispiel
public static void setNimbusUI(final IMethod<UIDefaults> method)
throws UnsupportedLookAndFeelException {
//NimbusLookAndFeel may be now available
UIManager.setLookAndFeel(new NimbusLookAndFeel() {
@Override
public UIDefaults getDefaults() {
UIDefaults ret = super.getDefaults();
method.perform(ret);
return ret;
}
});
}
BEARBEITEN:
Nun bearbeitete ich meinen code, so wie es vorgeschlagen wurde, abzufangen NoClassDefFoundError
mit try-catch. Es fehlschlägt. Ich weiß nicht, ob es OpenJDK ist Schuld. Ich bekomme InvocationTargetException
, verursacht durch NoClassDefFoundError
. Komisch, dass ich nicht fangen InvocationTargetException
: Es ist geworfen sowieso.
EDIT2::
Ursache gefunden: ich war wrapping SwingUtilities.invokeAndWait(...)
rund um die erprobte Methode, und das sehr invokeAndWait
Anruf wirft NoClassDefFoundError
beim laden Nimbus ausfällt.
EDIT3::
Kann jemand bitte klären, wo NoClassDefFoundError
können bei allen auftreten? Denn es scheint, dass es immer auf die aufrufende Methode, nicht die tatsächliche Methode, die verwendet die nicht vorhandene Klasse.
NoClassDefFoundError
tritt beim laden einer Klasse, die anwesend war in der compile-Zeit classpath, aber ist nicht in der runtime-classpath. ClassNotFoundException
tritt beim laden einer Klasse, die ist nicht in der runtime-classpath, aber nicht müssen vorhanden sein, in compile-Zeit classpath.@BalusC
: Meine Frage in EDIT3 war mit EDIT2: Ist irgendwo angegeben, dass NoClassDefFoundError
Auftritt, sagen wir mal, während der Konstruktion der Klasse, die versucht, rufen Sie eine andere nicht-vorhandenen Klasse, oder tritt es nur, wenn die - Methode, welche Anrufe die nicht vorhandene Klasse aufgerufen wird, ... Mehr Allgemeine: wo angegeben ist wenn eine bestimmte Klasse geladen wird?InformationsquelleAutor java.is.for.desktop | 2010-08-07
Du musst angemeldet sein, um einen Kommentar abzugeben.
Um es kennen zu lernen, die Klasse steht (zur Laufzeit)
Setzen Sie den Einsatz in einem try-block ...
Wenn es nicht der Fall ist, überspringen Sie die ganze Sache
... und verlassen der catch-block leer ist (code smell?!).
Wie verwalte ich eine Methode überschreiben einer dynamisch geladenen Klasse
Tun Sie es einfach und stellen Sie sicher, dass der compile-time-Abhängigkeit ist zufrieden. Mischen Sie die Dinge hier. Das überschreiben erfolgt zur compile-Zeit, während die Klasse be ist eine runtime-Ding.
Für die Vollständigkeit, jede Klasse, die Sie schreiben, die dynamisch geladen werden von der Laufzeitumgebung, wenn es erforderlich ist.
Sodass Ihr code kann wie folgt Aussehen:
OpenJDK 6
, so dass ich verwirrt wurde durch compile-time errors).... natürlich die optimale Lösung würde mir ermöglichen, zu kompilieren, die eventuell nicht vorhandenen Klasse auf Wunsch.
Vorausgesetzt, dieser code kompiliert wurde, wird nicht werfen eine
ClassNotFoundException
aber einNoClassDefFoundError
wennNimbusLookAndFeel
ist es nicht an der Laufzeit.Thivent: Recht! "exception ClassNotFoundException is never thrown in body of corresponding try statement". Aber sind Sie sicher, dass
NoClassDefFoundError
geworfen wird in der Methode? (Nicht, zum Beispiel, die von der Klasse' ctor, statische ctor, ... oder was auch immer...)vielen Dank für diesen Hinweis, es behoben
InformationsquelleAutor whiskeysierra
Verwenden BCEL generieren, die Ihre dynamische Unterklasse on-the-fly.
http://jakarta.apache.org/bcel/manual.html
Ich denke nicht so. Die nächste Sache, eingebaut in das JDK ist in der Proxy-Klasse, aber das wird nicht eine Unterklasse so nicht helfen. Letztlich wird eine neue Klasse erstellt werden on the fly", was bedeutet, dass die Generierung der bytecode der Klasse, und laden Sie es durch einen ClassLoader. Java bietet zwar nicht viele Optionen für diese-ohne eine Drittanbieter-Bibliothek wie BCEL.
Ja, proxies sind leider nur für das implementieren von Schnittstellen.
InformationsquelleAutor Kirk Woll
Der folgende code sollte dein problem lösen. Die
Main
Klasse simuliert Ihre main-Klasse. KlasseA
simuliert die Basisklasse, die Sie erweitern möchten (und Sie keine Kontrolle haben). KlasseB
ist die abgeleitete Klasse der KlasseA
. SchnittstelleC
simuliert "function pointer" - Funktion, die in Java nicht haben. Mal sehen, der erste code...Folgenden ist Klasse
A
, die Klasse, die Sie erweitern möchten, aber keine Kontrolle haben:Folgenden ist Klasse
B
die dummy-abgeleitete Klasse. Beachten Sie, dass, da es sichA
es importieren musspackageA.A
und KlasseA
muss bei der Kompilierung der KlasseB
. Ein Konstruktor mit dem parameter-C ist wichtig, aber die Umsetzung-SchnittstelleC
ist optional. WennB
implementiertC
erhalten Sie die Bequemlichkeit zum Aufruf der Methode(N) auf eine Instanz vonB
direkt (ohne Reflexion). InB.doSomething()
Aufrufsuper.doSomething()
ist optional und hängt davon ab, ob Sie so wollen, aber das aufrufenc.doSomething()
wesentlich ist (siehe unten):Folgenden ist die knifflige Schnittstelle
C
. Setzen Sie einfach alle Methoden, die Sie überschreiben möchten in dieser Schnittstelle:Folgenden ist die main-Klasse:
Warum ist es kompilieren und ausführen?
Sie können sehen, dass in der
Main
Klasse, nurpackageC.C
importiert, und es gibt keinen Verweis aufpackageA.A
oderpackageB.B
. Wenn es irgendeine, der class-loader wird eine exception werfen Sie auf Plattformen, die nichtpackageA.A
wenn er versucht zu laden.Wie funktioniert es?
In der ersten
Class.forName()
Sie prüft, ob KlasseA
ist auf der Plattform zur Verfügung. Wenn es so ist, Fragen Sie den class loader der classB
, und speichern Sie die resultierendeClass
Objekt inclassB
. AnsonstenClassNotFoundException
ausgelöst durchClass.forName()
, und das Programm geht auch ohne KlasseA
.Dann, wenn
classB
nicht null ist, bekommt der Konstruktor der KlasseB
akzeptiert eine einzelneC
- Objekt als parameter. Speichern Sie dieConstructor
Objekt inconstructorB
.Dann, wenn
constructorB
ist nicht null, rufen SieconstructorB.newInstance()
zu erstellenB
Objekt. Da gibt es eineC
- Objekt als parameter, können Sie erstellen Sie eine anonyme Klasse implementiert das interfaceC
und übergeben Sie die Instanz, die als parameter-Wert. Das ist genau wie das, was Sie tun, wenn Sie erstellen eine anonymeMouseListener
.(In der Tat, Sie nicht trennen zu müssen die oben
try
Blöcke. Es wird so getan, klar zu machen, was ich Tue.)Wenn Sie
B
implementiertC
, können Sie werfen dieB
Objekt alsC
Referenz an diese Zeit, und dann können Sie den Aufruf der überschriebenen Methoden direkt (ohne Reflexion).Was ist, wenn Klasse
A
Sie nicht "keine parameter-Konstruktor"?Fügen Sie einfach die erforderlichen Parameter zur Klasse
B
wiepublic B(int extraParam, C c)
, und rufen Siesuper(extraParam)
stattsuper()
. Bei der Erstellung derconstructorB
können, fügen Sie auch die zusätzlichen parameter, wieclassB.getConstructor(Integer.TYPE, C.class)
.Was passiert String
s
- und String -t
?t
verwendet wird, die durch die anonyme Klasse direkt. WennobjectB.doSomething("World");
genannt wird,"World"
ist dies
geliefert-KlasseB
. Dasuper
können nicht verwendet werden, in der die anonyme Klasse (aus offensichtlichen Gründen), der gesamte code, verwendensuper
sind platziert in KlasseB
.Was ist, wenn ich reden will
super
mehrmals verwenden?Schreiben Sie einfach eine Vorlage in
B.doSomething()
wie diese:Natürlich, Sie haben zu ändern-Schnittstelle
C
zu gehörendoSomethingAfter1()
unddoSomethingAfter2()
.Wie zu kompilieren und den code auszuführen?
Im ersten Lauf der Klasse
packageB.B
wird nicht kompiliert (daMain.java
keine Referenz). In der zweiten Ausführung, die Klasse wird kompiliert, und damit Sie das Ergebnis bekommen, das Sie erwartet.Helfen Sie passt meine Lösung zu deinem problem, hier ist ein link zu den richtigen Weg, um das Nimbus Look and Feel:
Nimbus Look and Feel
InformationsquelleAutor Siu Ching Pong -Asuka Kenji-
Können Sie Klasse Klasse zu tun.
I. E.:
Den Satz oben wirft eine ClassNotFoundException, wenn nicht gefunden im aktuellen Klassenpfad befinden. Wenn die Ausnahme nicht ausgelöst wird, dann können Sie
newInstance()
Methode inc
zum erstellen von Objekten von Ihr.Paket.YourClass Klasse. Wenn Sie brauchen, um das aufrufen einer speziellen Konstruktor, den Sie verwenden könnengetConstructors
Methode, eins zu bekommen und es verwenden, um eine neue Instanz zu erstellen.Ich sehe... Gute Frage. Lass mich mal nachdenken...
InformationsquelleAutor Pablo Santa Cruz
Ähm, können Sie dann nicht die Klasse, die Sie erweitern möchten, in die compile-Zeit "class path", schreiben die Unterklasse als üblich, und zur Laufzeit explizit trigger laden der Unterklasse, und behandeln jede Ausnahme, die ausgelöst durch den linker, der angibt, dass die Oberklasse fehlt?
InformationsquelleAutor meriton