Was ist in Java der Unterschied zwischen diesen:
Object o1 = ....
o1.getClass().getSimpleName();
o1.getClass().getName();
o1.getClass().getCanonicalName();
Ich habe das Javadoc mehrmals überprüft und dies erklärt es nie gut. Ich habe auch einen Test durchgeführt, der keine wirkliche Bedeutung für die Art und Weise hatte, wie diese Methoden aufgerufen werden.
Antworten:
Wenn Sie sich bei etwas nicht sicher sind, schreiben Sie zuerst einen Test.
Ich war das:
Drucke:
Im letzten Block befindet sich ein leerer Eintrag, in dem
getSimpleName
eine leere Zeichenfolge zurückgegeben wird.Das Ergebnis ist:
Class.forName
mit der StandardeinstellungClassLoader
. Im Rahmen eines bestimmtenClassLoader
haben alle Klassen eindeutige Namen.toString
oder während der Protokollierung hilfreich sein . Wenn derjavac
Compiler die vollständige Ansicht eines Klassenpfads hat, erzwingt er die Eindeutigkeit der darin enthaltenen kanonischen Namen, indem er beim Kompilieren vollständig qualifizierte Klassen- und Paketnamen in Konflikt bringt. JVMs müssen jedoch solche Namenskonflikte akzeptieren, und daher identifizieren kanonische Namen Klassen innerhalb von a nicht eindeutigClassLoader
. (Im Nachhinein wäre ein besserer Name für diesen Getter gewesengetJavaName
; diese Methode stammt jedoch aus einer Zeit, als die JVM ausschließlich zum Ausführen von Java-Programmen verwendet wurde.)toString
oder bei Protokollierungsvorgängen nützlich sein , ist jedoch nicht garantiert eindeutig.quelle
Hinzufügen lokaler Klassen, Lambdas und der
toString()
Methode zum Vervollständigen der beiden vorherigen Antworten. Außerdem füge ich Arrays von Lambdas und Arrays anonymer Klassen hinzu (die in der Praxis jedoch keinen Sinn ergeben):Dies ist die vollständige Ausgabe:
Also, hier sind die Regeln. Beginnen wir zunächst mit primitiven Typen und
void
:void
, geben alle vier Methoden einfach seinen Namen zurück.Nun die Regeln für die
getName()
Methode:getName()
), bei dem es sich um den Paketnamen handelt, gefolgt von einem Punkt (falls ein Paket vorhanden ist) ), gefolgt vom Namen der vom Compiler generierten Klassendatei (ohne Suffix.class
). Wenn es kein Paket gibt, ist es einfach der Name der Klassendatei. Wenn die Klasse eine innere, verschachtelte, lokale oder anonyme Klasse ist, sollte der Compiler mindestens eine$
in seinem Klassendateinamen generieren . Beachten Sie, dass bei anonymen Klassen der Klassenname mit einem Dollarzeichen gefolgt von einer Zahl endet.$$Lambda$
einer Zahl, gefolgt von einem Schrägstrich, gefolgt von einer anderen Zahl.Z
fürboolean
,B
fürbyte
,S
fürshort
,C
fürchar
,I
fürint
,J
fürlong
,F
fürfloat
undD
fürdouble
. Bei Nicht-Array-Klassen und -SchnittstellenL
folgt auf den Klassendeskriptor das, wasgetName()
gefolgt von gefolgt wird;
. Bei Array-Klassen[
folgt auf den Klassendeskriptor der Klassendeskriptor des Komponententyps (der selbst eine andere Array-Klasse sein kann).getName()
Methode ihren Klassendeskriptor zurück. Diese Regel scheint nur für Array-Klassen fehlzuschlagen, deren Komponententyp ein Lambda ist (was möglicherweise ein Fehler ist), aber hoffentlich sollte dies sowieso keine Rolle spielen, da selbst die Existenz von Array-Klassen, deren Komponententyp ein Lambda ist, keinen Sinn macht.Nun die
toString()
Methode:toString()
zurückgegeben"interface " + getName()
. Wenn es ein Grundelement ist, kehrt es einfach zurückgetName()
. Wenn es etwas anderes ist (ein Klassentyp, auch wenn es ein ziemlich seltsamer Typ ist), kehrt er zurück"class " + getName()
.Die
getCanonicalName()
Methode:getCanonicalName()
Methode genau das zurück, was diegetName()
Methode zurückgibt.getCanonicalName()
Methode gibtnull
für anonyme oder lokale Klassen und für Array-Klassen dieser Klassen zurück.getCanonicalName()
Methode zurück, was diegetName()
Methode die vom Compiler eingeführten Dollarzeichen durch Punkte ersetzen würde.getCanonicalName()
Methode zurück,null
wenn der kanonische Name des Komponententyps lautetnull
. Andernfalls wird der kanonische Name des Komponententyps zurückgegeben, gefolgt von[]
.Die
getSimpleName()
Methode:getSimpleName()
gibt der den Namen der Klasse zurück, wie er in der Quelldatei geschrieben ist.getSimpleName()
eine leere zurückgegebenString
.getSimpleName()
nur das zurück, wasgetName()
ohne den Paketnamen zurückgegeben werden würde. Das macht nicht viel Sinn und sieht für mich wie ein Fehler aus, aber es macht keinen Sinn, zunächstgetSimpleName()
eine Lambda-Klasse aufzurufen .getSimpleName()
Methode den einfachen Namen der Komponentenklasse zurück, gefolgt von[]
. Dies hat den lustigen / seltsamen Nebeneffekt, dass Array-Klassen, deren Komponententyp eine anonyme Klasse ist, genauso[]
einfache Namen haben.quelle
… replacing the dollar-signs by dots
: Nur die als Trennzeichen eingeführten Dollarzeichen werden ersetzt. Sie können Dollars als Teil eines einfachen Namens haben, und diese bleiben an Ort und Stelle.Zusätzlich zu den Beobachtungen von Nick Holt habe ich einige Fälle für den
Array
Datentyp ausgeführt:Über Code-Snippet druckt:
quelle
Ich war auch verwirrt über die Vielzahl der verschiedenen Namensschemata und wollte gerade meine eigene Frage dazu stellen und beantworten, als ich diese Frage hier fand. Ich denke, meine Ergebnisse passen gut genug und ergänzen das, was bereits hier ist. Mein Fokus liegt auf der Suche nach Dokumentation zu den verschiedenen Begriffen und dem Hinzufügen weiterer verwandter Begriffe, die an anderen Stellen auftauchen könnten.
Betrachten Sie das folgende Beispiel:
Der einfache Name von
D
istD
. Das ist nur der Teil, den Sie geschrieben haben, als Sie die Klasse deklariert haben. Anonyme Klassen haben keinen einfachen Namen.Class.getSimpleName()
Gibt diesen Namen oder die leere Zeichenfolge zurück. Es ist möglich, dass der einfache Name ein enthält,$
wenn Sie ihn so schreiben, da er$
ein gültiger Teil eines Bezeichners gemäß JLS-Abschnitt 3.8 ist (auch wenn er etwas entmutigt ist).Gemäß dem JLS-Abschnitt 6.7 wären beide
a.b.C.D
und vollständig qualifizierte Namen , aber nur der kanonische Name von . Jeder kanonische Name ist also ein vollständig qualifizierter Name, aber das Gegenteil ist nicht immer der Fall. gibt den kanonischen Namen zurück oder .a.b.C.D.D.D
a.b.C.D
D
Class.getCanonicalName()
null
Class.getName()
wird dokumentiert, um den Binärnamen zurückzugeben , wie in JLS-Abschnitt 13.1 angegeben . In diesem Fall wirda.b.C$D
fürD
und[La.b.C$D;
für zurückgegebenD[]
.Diese Antwort zeigt, dass zwei Klassen, die von demselben Klassenlader geladen werden, denselben kanonischen Namen, aber unterschiedliche Binärnamen haben können . Keiner der beiden Namen reicht aus, um den anderen zuverlässig abzuleiten: Wenn Sie den kanonischen Namen haben, wissen Sie nicht, welche Teile des Namens Pakete sind und welche Klassen enthalten. Wenn Sie den Binärnamen haben, wissen Sie nicht, welche
$
als Trennzeichen eingeführt wurden und welche Teil eines einfachen Namens waren. (In der Klassendatei werden der Binärname der Klasse selbst und ihre umschließende Klasse gespeichert , sodass die Laufzeit diese Unterscheidung treffen kann .)Anonyme Klassen und lokale Klassen haben keine vollständig qualifizierten Namen, aber dennoch einen Binärnamen . Gleiches gilt für Klassen, die in solchen Klassen verschachtelt sind. Jede Klasse hat einen binären Namen.
Das Ausführen
javap -v -private
vona/b/C.class
zeigt, dass sich der Bytecode auf den Typ vond
asLa/b/C$D;
und den des Arraysds
als bezieht[La/b/C$D;
. Diese werden als Deskriptoren bezeichnet und sind in Abschnitt 4.3 von JVMS angegeben .Der
a/b/C$D
in diesen beiden Deskriptoren verwendete Klassenname wird durch Ersetzen.
durch/
den Binärnamen erhalten. Die JVM-Spezifikation nennt dies anscheinend die interne Form des Binärnamens . JVMS-Abschnitt 4.2.1 beschreibt es und gibt an, dass der Unterschied zum Binärnamen aus historischen Gründen bestand.Der Dateiname einer Klasse in einem der typischen auf Dateinamen basierenden Klassenladeprogramme wird angezeigt, wenn Sie den Dateinamen
/
in der internen Form als Verzeichnistrennzeichen interpretieren und die Dateinamenerweiterung.class
an ihn anhängen . Es wird relativ zum Klassenpfad aufgelöst, der vom betreffenden Klassenlader verwendet wird.quelle
Dies ist das beste Dokument, das ich gefunden habe, um getName (), getSimpleName (), getCanonicalName () zu beschreiben.
https://javahowtodoit.wordpress.com/2014/09/09/java-lang-class-what-is-the-difference-between-class-getname-class-getcanonicalname-and-class-getsimplename/
quelle
Es ist interessant zu bemerken, dass
getCanonicalName()
undgetSimpleName()
kann erhöhen,InternalError
wenn der Klassenname fehlerhaft ist. Dies geschieht für einige Nicht-Java-JVM-Sprachen, z. B. Scala.Beachten Sie Folgendes (Scala 2.11 unter Java 8):
Dies kann ein Problem für Umgebungen mit gemischten Sprachen oder Umgebungen sein, in denen Bytecode dynamisch geladen wird, z. B. App-Server und andere Plattformsoftware.
quelle
getName () - Gibt den Namen der Entität (Klasse, Schnittstelle, Array-Klasse, primitiver Typ oder void), die von diesem Class-Objekt dargestellt wird, als String zurück.
getCanonicalName () - gibt den kanonischen Namen der zugrunde liegenden Klasse zurück, wie in der Java-Sprachspezifikation definiert.
getSimpleName () - gibt den einfachen Namen der zugrunde liegenden Klasse zurück, dh den Namen, den sie im Quellcode angegeben hat.
Ein Unterschied besteht darin, dass Sie bei Verwendung einer anonymen Klasse einen Nullwert erhalten können, wenn Sie versuchen, den Namen der Klasse mithilfe von zu ermitteln
getCanonicalName()
Eine andere Tatsache ist, dass sich die
getName()
Methode anders verhält als diegetCanonicalName()
Methode für innere Klassen .getName()
verwendet einen Dollar als Trennzeichen zwischen dem kanonischen Namen der umschließenden Klasse und dem einfachen Namen der inneren Klasse.Weitere Informationen zum Abrufen eines Klassennamens in Java .
quelle
quelle
Class<StringBuffer> clazz = StringBuffer.class