Einleitung: Drei Namen einer Klasse – wie vermeidet man Verwirrung?
Jeder Java-Entwickler, der sich jemals mit Reflection beschäftigt hat, ist auf drei scheinbar identische Methoden gestoßen: getName(), getSimpleName() und getCanonicalName(). Auf den ersten Blick geben sie alle den Klassennamen zurück. Aber sobald innere Klassen, Arrays oder anonyme Klassen ins Spiel kommen, beginnt die Verwirrung. Genau diese Frage hat tausende Aufrufe auf Stack Overflow gesammelt, und heute klären wir ein für alle Mal, worin der Unterschied besteht.
In diesem Artikel listen wir nicht nur die Definitionen auf, sondern zeigen anhand von echten Codebeispielen, wie diese Methoden funktionieren. Sie erfahren, wann Sie welche Methode verwenden sollten und welche Fallstricke auf Sie warten. Los geht's!
1. Grundlegende Konzepte: Was gibt jede Methode zurück?
Bevor wir in die Tiefe gehen, definieren wir, was diese Begriffe im Kontext der Java Class API bedeuten.
- Simple Name (
getSimpleName()): Der kürzeste Name. Es ist einfach der Klassenname ohne Paket. Für innere Klassen – nur der Name der innersten Klasse. - Class Name (
getName()): Der vollständige Name, jedoch unter Berücksichtigung der internen JVM-Struktur. Für normale Klassen ist es package + class. Für innere Klassen wird das Trennzeichen$verwendet. Für Arrays werden eckige Klammern hinzugefügt. - Canonical Name (
getCanonicalName()): Der „kanonische“ Name, der im Quellcode zur Deklaration einer Variablen verwendet werden kann. Er ist dem, wie Sie Code schreiben, maximal angenähert: mit Punkten statt Dollarzeichen.
Klingt abstrakt? Lassen Sie uns das mit Code untermauern.
2. Beispiel mit einer normalen Klasse
Beginnen wir mit dem Einfachsten – einer normalen Klasse ohne Verschachtelungen.
// Datei: com/example/MyClass.javapackage com.example;
public class MyClass { public static void main(String[] args) { System.out.println("Simple Name: " + MyClass.class.getSimpleName()); System.out.println("Class Name: " + MyClass.class.getName()); System.out.println("Canonical Name: " + MyClass.class.getCanonicalName()); }}Ergebnis:
Simple Name: MyClassClass Name: com.example.MyClassCanonical Name: com.example.MyClassWie Sie sehen, sind getName() und getCanonicalName() bei einer normalen Klasse absolut identisch. getSimpleName() lässt das Paket weg. Keine Magie.
3. Innere (verschachtelte) Klassen: Wo die Magie beginnt
Stellen Sie sich nun vor, wir haben eine innere Klasse. Hier zeigt sich der entscheidende Unterschied.
package com.example;
public class OuterClass { public static class InnerClass { public void printNames() { System.out.println("Simple: " + getClass().getSimpleName()); System.out.println("Class: " + getClass().getName()); System.out.println("Canonical: " + getClass().getCanonicalName()); } }
public static void main(String[] args) { InnerClass inner = new InnerClass(); inner.printNames(); }}Ergebnis:
Simple: InnerClassClass: com.example.OuterClass$InnerClassCanonical: com.example.OuterClass.InnerClassDa ist es! Der Unterschied wird offensichtlich:
getSimpleName()gab einfachInnerClasszurück.getName()verwendet das Symbol$zur Trennung von Eltern- und innerer Klasse. Dies ist die interne Darstellung der JVM.getCanonicalName()verwendet einen Punkt – so, wie Sie es im Code schreiben würden:OuterClass.InnerClass.
Genau wegen dieses $-Symbols fangen viele Anfänger Bugs ein, wenn sie versuchen, eine Klasse über <