Wie kann man den Namen der Klasse von einer statischen Methode in dieser Klasse erhalten? Beispielsweise
public class MyClass {
public static String getClassName() {
String name = ????; // what goes here so the string "MyClass" is returned
return name;
}
}
Um es in einen Kontext zu setzen, möchte ich den Klassennamen tatsächlich als Teil einer Nachricht in einer Ausnahme zurückgeben.
try{ throw new RuntimeEsception();} catch(RuntimeEcxeption e){return e.getstackTrace()[1].getClassName();
}Antworten:
Um das Refactoring korrekt zu unterstützen (Klasse umbenennen), sollten Sie Folgendes verwenden:
oder (danke an @James Van Huis ):
quelle
Mach was das Toolkit sagt. Mach so etwas nicht:
quelle
getClass
gibt den Laufzeittyp zurück, kann also nicht statisch sein.In Java 7+ können Sie dies in statischen Methoden / Feldern tun:
quelle
Reflection.getCallerClass()
. Aber es gibt eine Warnung davor, in den "Sonnen" -Paketen zu sein. Dies könnte also eine bessere Lösung sein.Reflection.getCallerClass()
Sache ersetzen wird . Es ist ein bisschen kompliziert für seine triviale Operation, dhOptional<Class<?>> myself = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE) .walk(s -> s.map(StackWalker.StackFrame::getDeclaringClass) .findFirst());
natürlich hängt das damit zusammen, dass es viel mächtiger sein wird.Wir haben also eine Situation, in der wir ein Klassenobjekt oder einen vollständigen / einfachen Klassennamen ohne explizite Verwendung von statisch abrufen müssen
MyClass.class
Syntax abrufen müssen.In einigen Fällen kann es sehr praktisch sein, z. B. eine Logger-Instanz für die Kotlin Funktionen der oberen Ebene (in diesem Fall erstellt kotlin eine statische Java-Klasse, auf die über den kotlin-Code nicht zugegriffen werden kann).
Wir haben verschiedene Varianten, um diese Informationen zu erhalten:
new Object(){}.getClass().getEnclosingClass();
notiert von Tom Hawtin - Tackline
getClassContext()[0].getName();
aus demSecurityManager
von Christoffer notierten
new Throwable().getStackTrace()[0].getClassName();
von Graf Ludwig
Thread.currentThread().getStackTrace()[1].getClassName();
von Keksi
und schließlich super
MethodHandles.lookup().lookupClass();
von Rein
Ich habe eine vorbereitet jmh Benchmark für alle Varianten und Ergebnisse sind:
Schlussfolgerungen
Verfügbar nur seit Java 7 und Android API 26!
Wenn Sie es an vielen Orten benötigen und nicht möchten, dass Ihr Bytecode aufgrund unzähliger anonymer Klassen aufgebläht wird,
SecurityManager
ist dies Ihr Freund (drittbeste Option).Aber Sie können nicht einfach anrufen
getClassContext()
- es ist in derSecurityManager
Klasse geschützt . Sie benötigen eine Helferklasse wie diese:getStackTrace()
from-Ausnahme oder der from-Ausnahme basierenThread.currentThread()
. Sehr ineffizient und kann nur den Klassennamen alsString
, nicht dieClass<*>
Instanz zurückgeben.PS
Wenn Sie eine Logger-Instanz für statische Kotlin-Utils erstellen möchten (wie ich :), können Sie diesen Helfer verwenden:
Anwendungsbeispiel:
quelle
Diese Anweisung funktioniert gut:
quelle
Thread.getStackTrace()
ansehen, werden Sie feststellen, dass er nichts anderes tut, alsreturn (new Exception()).getStackTrace();
wenn er auf dem aufgerufen wirdcurrentThread()
. Die Lösung von @count ludwig ist also der direktere Weg, um dasselbe zu erreichen.Sie könnten etwas wirklich Süßes tun, indem Sie JNI wie folgt verwenden:
MyObject.java:
dann:
dann:
MyObject.c:
Kompilieren Sie dann das C in eine gemeinsam genutzte Bibliothek mit dem Namen
libclassname.so
und führen Sie Java aus!*Kichern
quelle
Java_MyObject_getClassName
den Namen eingebettet hat. Der Weg dahin ist die Verwendung des JNIRegisterNatives
. Natürlich müsste man das mit dem JNI fütternFindClass(env, 'com/example/MyObject')
, also auch dort kein Gewinn.private static final String TAG = "MyClass"
oderprivate static final String TAG = MyClass.class.getSimpleName();
Die zweite ist für das Umbenennen globaler Klassen mithilfe einer IDE benutzerfreundlicher.Ich verwende dies, um den Log4j-Logger oben in meinen Klassen zu starten (oder zu kommentieren).
PRO: Throwable ist bereits geladen und Sie können Ressourcen sparen, wenn Sie den SecurityManager "IO heavy" nicht verwenden.
CON: Einige Fragen, ob dies für alle JVMs funktioniert.
quelle
Missbrauche den SecurityManager
Oder, falls nicht festgelegt, verwenden Sie eine innere Klasse, die sie erweitert (Beispiel unten, schändlich kopiert von Real's HowTo ):
quelle
Wenn Sie den gesamten Paketnamen damit haben möchten, rufen Sie an:
Wenn Sie nur das letzte Element möchten, rufen Sie auf:
quelle
Die wörtliche Verwendung der Klasse des Aufrufers wie
MyClass.class.getName()
tatsächlich erledigt den Job, ist jedoch anfällig für das Kopieren / Einfügen von Fehlern, wenn Sie diesen Code an zahlreiche Klassen / Unterklassen weitergeben, in denen Sie diesen Klassennamen benötigen.Und Tom Hawtins Rezept ist in der Tat nicht schlecht, man muss es nur richtig kochen :)
Wenn Sie eine Basisklasse mit einer statischen Methode haben, die aus Unterklassen aufgerufen werden kann, und diese statische Methode die Klasse des tatsächlichen Aufrufers kennen muss, kann dies wie folgt erreicht werden:
quelle
Eine Refactoring-sichere, Cut & Paste-sichere Lösung, die die Definition der folgenden Ad-hoc-Klassen vermeidet.
Schreiben Sie eine statische Methode, die den Klassennamen wiederherstellt, wobei Sie darauf achten, den Klassennamen in den Methodennamen aufzunehmen:
Rufen Sie es dann in Ihrer statischen Methode auf:
Die Refactoring-Sicherheit wird durch die Vermeidung der Verwendung von Zeichenfolgen gewährleistet. Die Sicherheit zum Ausschneiden und Einfügen wird gewährleistet, da beim Ausschneiden und Einfügen der Aufrufermethode die getMyClassName () in der Zielklasse "MyClass2" nicht gefunden wird und Sie daher gezwungen sind, sie neu zu definieren und zu aktualisieren.
quelle
Seit der Frage Etwas wie "this.class" anstelle von "ClassName.class"? ist als Duplikat für dieses markiert (was fraglich ist, da es sich bei dieser Frage eher um die Klasse als um den Klassennamen handelt). Ich poste die Antwort hier:
Es ist wichtig,
thisClass
als privat zu definieren, weil:1) es nicht vererbt werden darf: abgeleitete Klassen müssen entweder ihre eigenen definieren
thisClass
oder eine Fehlermeldung erzeugen.2) Verweise von anderen Klassen sollten wie
ClassName.class
folgt erfolgenClassName.thisClass
.Mit
thisClass
defined wird der Zugriff auf den Klassennamen wie folgt:quelle
Ich brauchte den Klassennamen in den statischen Methoden mehrerer Klassen, also implementierte ich eine JavaUtil-Klasse mit der folgenden Methode:
Hoffe es wird helfen!
quelle
Ich habe diese beiden Ansätze für beide
static
undnon static
Szenarien verwendet:Hauptklasse:
So geben Sie den Klassennamen an:
nicht statischer Weg:
Statischer Weg:
quelle
Wenn Sie Reflection verwenden, können Sie das Method-Objekt abrufen und dann:
Um die Methode selbst zu erhalten, können Sie wahrscheinlich Folgendes verwenden:
quelle
Class.forName("class name")
dir schon eine Klasse gegeben. Warum möchten Sie es über die Methode abrufen?