2012-03-27 3 views
8

Ich habe eine Zeichenfolge mit einem gewissen Wert. Ich möchte über alle Klassen in einem Paket iterieren, indem ich eine bestimmte Methode aufruft. Wenn der von der Methode zurückgegebene Wert dem Wert in meiner Zeichenfolge entspricht, erstellen Sie ein Objekt dieser Klasse.Ist es möglich, über alle Klassen innerhalb eines Pakets mit Reflection zu iterieren?

Ich möchte dies auf eine dynamische Weise tun, wenn ich also eine Klasse in diesem Paket hinzufüge, wird es automatisch in der Iteration sein.

Ist das möglich? Wenn nicht, gibt es eine Möglichkeit zu tun, was ich will?


Ich hatte etwas erwartet.

for(Class clazz: SomeClass.listClasses("org.package")){ 
    //code here 
} 
+0

Was bedeutet "eine Klasse in diesem Paket hinzufügen"? Wie kommt es in den Klassenpfad des Java-Prozesses? –

+0

@ Jeffrey Ich habe über Reflection gelesen und ich denke, das ist der einzige Weg, aber ich weiß nichts über Reflection. Ich habe einen "normalen Weg" versucht, indem ich eine Überprüfung für jede Klasse, die ich in diesem Paket habe, hinzufüge, aber ich möchte diesen Weg nicht, weil er nicht erweiterbar ist. –

+0

@MiserableVariable In der Entwicklungszeit füge ich eine neue Klasse in das Paket ein (alle Klassen erweitern eine abstrakte Klasse namens Document). –

Antwort

8

Nein, dies ist nicht absolut zuverlässig möglich; es kann jedoch in vielen Fällen sinnvoll sein, sie zu implementieren.

Aufgrund der Flexibilität von Java-Klassenladeprogrammen sind die unter einem bestimmten Paket definierten Klassen möglicherweise zur Laufzeit nicht bekannt (z. B. einen speziellen Klassenlader, der Klassen während des Betriebs definiert, z. B. durch Laden aus dem Netzwerk) kompiliert sie ad-hoc). Daher gibt es keine Standard-Java-API, mit der Sie die Klassen in einem Paket auflisten können.

Praktisch können Sie jedoch einige Tricks ausführen, indem Sie den Klassenpfad nach allen Klassen- und JAR-Dateien durchsuchen, eine Sammlung vollständig qualifizierter Klassennamen erstellen und diese nach Bedarf durchsuchen. Diese Strategie funktioniert gut, wenn Sie sicher sind, dass sich kein aktiver Klassenlader wie im vorherigen Absatz beschrieben verhält. Zum Beispiel (Java Pseudocode):

Map<String, Set<String>> classesInPackage = new HashMap(); 
for (String entry : eachClasspathEntry()) { 
    if (isClassFile(entry)) { 
    String packageName = getPackageName(entry); 
    if (!classesInPackage.containsKey(packageName)) { 
     classesInPackage.put(packageName, new HashSet<String>()); 
    } 
    classesInPackage.get(packageName).add(getClassName(entry)); 
    } else if (isJarOrZipFile(entry)) { 
    // Do the same for each JAR/ZIP file entry... 
    } 
} 
classesInPackage.get("com.foo.bar"); // => Set<String> of each class... 
+0

Aber ein Custom Classloader könnte, zumindest in der Theorie. –

+0

@MiserableVariable: imagine Ich habe einen benutzerdefinierten Classloader geschrieben, der die Methode 'defineClass (String)' implementiert, indem er den Bytecode für eine Klasse zurückgibt, die eine leere Klasse durch den gegebenen Klassennamen definiert. Dies ist ein vollständig gültiger Classloader und es gibt keine (praktische) Möglichkeit, jede Klasse aufzulisten, die sie definieren könnte. – maerics

+0

Ja, im Allgemeinen ist das Problem nicht lösbar. Aber es ist anders für eine bestimmte enge Situation - ich könnte alle .class-Dateien in einem Ordner namens 'plugins' überprüfen und eine Instanz für jede Klasse erstellen wollen, die eine 'register'-Methode hat. –

1

Ja, aber nicht als allgemeine Falllösung. Sie müssen Ihren Code packen und die JVM auf spezifische Weise aufrufen. Insbesondere müssen Sie einen Instrumentierungsagenten erstellen und java.lang.instrument.Instrumentation.getAllLoadedClasses() aufrufen.

Das Paket documentation for java.lang.instrument enthält viele Details zum Erstellen und Instanziieren eines Agenten.

+0

Er möchte nicht nur geladene Klassen, sondern (vermutlich) alle neuen Klassen in einem Ordner im Klassenpfad –

+0

@MiserableVariable. Ich weiß nicht, ob es klar ist, aber die Klassen, die ich laden will, sind in der Entwicklungszeit definiert in der Laufzeit. –

2

Ich kann mir zwei Möglichkeiten vorstellen, um das zu lösen, von dem ich glaube, dass es ein Problem ist, auch wenn nicht alle Klassen in einem Paket durchlaufen werden.

Eine besteht darin, eine separate Datei zu erstellen, die Klassen auflistet, auf denen diese spezifische Methode aufgerufen werden soll. Dies ist ziemlich einfach zu implementieren. Möglicherweise haben Sie etwas Arbeit, um die Datei zu erstellen, aber das könnte automatisiert werden.

Die zweite Option besteht darin, nach .class-Dateien an einem bekannten Ort zu suchen - sagen wir einen einzelnen Ordner oder eine Gruppe von Ordnern - und raten Sie, was der Klassenname wäre und laden Sie ihn. Wenn dies ein einfacher Entwicklungsprozess ist, befinden sich die Klassendateien aus einem einzelnen Paket wahrscheinlich in einem einzigen Verzeichnis.

Verwandte Themen