HOWTO · Java

Ermitteln des Klassennamens in Java

Dieser Artikel zeigt, wie man den Klassennamen in Java erhält

Auf dieser Seite

Um einen Java-Klassennamen zu erhalten, entscheiden Sie zuerst, welche Darstellung Sie benötigen. Rufen Sie bei einem Objekt getClass() auf, um dessen Laufzeitobjekt vom Typ Class<?> zu erhalten. Rufen Sie anschließend für diese Klasse getSimpleName(), getName() oder getCanonicalName() auf. Ist der Typ bereits bekannt, verwenden Sie ein Klassenliteral wie String.class. Die drei Methoden zur Namensabfrage unterscheiden sich bei verschachtelten und besonderen Klassen; ihre Ergebnisse sind daher nicht austauschbar.

Wählen Sie die benötigte Darstellung des Klassennamens

Verwenden Sie getSimpleName() für einen kurzen Anzeigenamen, getName() für den Binärnamen der JVM und getCanonicalName() für den kanonischen Namen in Quellcodeform, sofern ein solcher verfügbar ist. Der einfache Name enthält kein Paket. Der Binärname kann Paketpräfixe und $ als Trennzeichen für verschachtelte Typen enthalten. Im kanonischen Namen werden einschließende und verschachtelte Typen durch Punkte getrennt. Er ist jedoch nicht für jede Klasse verfügbar und kann null sein.

Diese Werte sind Namen und keine Class-Objekte. Sie eignen sich für die Anzeige, Diagnose und Untersuchungen im Zusammenhang mit Reflection. Verwenden Sie einen generierten Namen jedoch nicht als stabile Kennung für die Speicherung oder für externe Protokolle. Wenn der Typ bereits zur Compile-Zeit bekannt ist, können Sie mit einem Klassenliteral direkt darauf verweisen, ohne zuerst eine Instanz abzufragen.

Rufen Sie mit getClass() die Laufzeitklasse eines Objekts ab

getClass() ist eine von Object geerbte Instanzmethode. Sie gibt die tatsächliche Laufzeitklasse des Objekts als Class<?> zurück, nicht als Zeichenfolge. Das ist nützlich, wenn der deklarierte Typ einer Variablen allgemeiner ist als der Typ des Objekts, auf das sie verweist. So lässt sich beispielsweise trotz einer als Object deklarierten Variablen die Laufzeitklasse ihres aktuellen Werts ermitteln.

Führen Sie dieses Beispiel aus. Die Bezeichnungen im Code und die Ausgabe bleiben auf Englisch.

public class ClassNameExample {
    public static void main(String[] args) {
        Object value = "hello";
        Class<?> runtimeClass = value.getClass();

        System.out.println(runtimeClass.getSimpleName());
        System.out.println(runtimeClass.getName());
    }
}
String
java.lang.String

Die erste Zeile fragt den gut lesbaren einfachen Namen ab, die zweite den Binärnamen. Das Beispiel zeigt daher die Ausgabe String und java.lang.String; diese Bezeichnungen bleiben auf Englisch. Verwendet wird die Laufzeitklasse des Werts, also String, und nicht der deklarierte Typ der Variablen value (Object). Ist der Typ bereits bekannt, liefert String.class das zugehörige Objekt vom Typ Class<String>, ohne dass eine Zeichenfolgeninstanz erstellt werden muss.

Wählen Sie zwischen getSimpleName(), getName() und getCanonicalName()

Rufen Sie jede Methode zur Namensabfrage für ein Class<?>-Objekt auf. Für eine Klasse der obersten Ebene wie java.util.ArrayList gibt getSimpleName() den Wert ArrayList zurück, während getName() und getCanonicalName() jeweils java.util.ArrayList zurückgeben. Bei einer Memberklasse Outer.Inner lautet der einfache Name Inner. Im Binärnamen steht zwischen den Klassen ein $, im kanonischen Namen ein Punkt.

Methode Verwendung Typische Form
getSimpleName() Kurze Anzeige ArrayList
getName() Binärname der JVM java.util.ArrayList
getCanonicalName() Name in Quellcodeform, sofern verfügbar java.util.ArrayList

Das Paketpräfix erscheint, wenn die Klasse zu einem benannten Paket gehört. Klassen im Standardpaket haben kein Paketpräfix. getName() ist nicht immer ein vollständig qualifizierter Name in Quellcodeform: Arrayklassen verwenden JVM-Deskriptoren, und lokale oder anonyme Klassen haben generierte Binärnamen. Für lokale und anonyme Klassen kann getCanonicalName() null zurückgeben. Wählen Sie die Methode passend dazu, wie die Zeichenfolge verwendet wird, statt anzunehmen, eine davon liefere immer einen vollständig qualifizierten Namen.

Ein Klassenliteral funktioniert mit denselben Methoden. Zum Beispiel liefert String.class.getSimpleName() den einfachen Namen des bekannten Typs. Ist der Typ eines Objekts erst zur Laufzeit bekannt, rufen Sie zuerst value.getClass() auf.

Behandeln Sie anonyme und andere besondere Klassen

Anonyme Klassen haben keinen Namen auf Quellcodeebene. Die JVM weist ihnen generierte Binärnamen zu, die oft ein $ und eine Zahl enthalten. Die genaue Schreibweise hängt jedoch vom Compiler ab und ist nicht stabil. Für eine anonyme Klasse ist getSimpleName() eine leere Zeichenfolge und getCanonicalName() null; getName() gibt den generierten Binärnamen zurück.

Lokale Klassen werden innerhalb einer Methode oder eines Initialisierers deklariert. Auch sie haben generierte Binärnamen, und ihr kanonischer Name ist null. Memberklassen hingegen werden als Mitglieder einer anderen Klasse deklariert und haben einfache sowie kanonische Namen auf Quellcodeebene. Diese Unterschiede erklären, warum eine Methode zur Namensabfrage einen leeren oder null-Wert zurückgeben kann, obwohl getClass() die Laufzeitklasse erfolgreich ermittelt.

Benötigt ein Programm für eine anonyme oder lokale Implementierung eine verlässliche Bezeichnung, legen Sie diese ausdrücklich in der Anwendung fest. Zerlegen Sie keinen generierten Namen und leiten Sie daraus keinen für Benutzer bestimmten Typnamen ab.

Ermitteln Sie die Klasse des Aufrufers anhand eines Stacktraces

Ein Stacktrace lässt sich untersuchen, wenn Sie gezielt einen bestimmten Stackframe identifizieren müssen. Das ist jedoch weniger direkt, als getClass() für das betreffende Objekt aufzurufen. Thread.currentThread().getStackTrace() gibt ein Array mit StackTraceElement-Werten zurück. Bei jedem Element gibt getClassName() den für diesen Frame gespeicherten Klassennamen zurück. Die folgende Syntax zeigt, wie ein Frame ausgewählt wird. Der Index hängt jedoch vom Aufrufpfad und der Laufzeit ab; das Beispiel ist daher keine portable Methode, um einen beliebigen Aufrufer abzurufen:

Thread.currentThread().getStackTrace()[2].getClassName()

Auch die aktuelle Methode und die Methode, die den Stacktrace abruft, belegen jeweils einen Frame. Deshalb verweist Index 2 in einer einfachen Aufrufkette häufig auf den unmittelbaren Aufrufer. Wrapper-Methoden, virtuelle Maschinen und Laufzeitoptimierungen können beeinflussen, welche Frames vorhanden sind. Wenn Sie diese Technik zur Diagnose verwenden, prüfen Sie die Frame-Liste des konkreten Programms. Für die gewöhnliche Namensabfrage sollten Sie den Stack nicht durchlaufen. Gehört die Identität des Aufrufers zum API-Vertrag, übergeben Sie stattdessen das Objekt oder die Klasseninformationen direkt.