java - tutorial - jpanel
Was ist der Unterschied zwischen dem kanonischen Namen, dem einfachen Namen und dem Klassennamen in der Java-Klasse? (5)
In Java: Was ist der Unterschied zwischen:
Object o1= ....
o1.getClass().getSimpleName();
o1.getClass().getName();
o1.getClass().getCanonicalName();
?
AKTUALISIEREN
Ich habe das Javadoc schon mehrfach überprüft und trotzdem erklärt es das nie gut. Ich habe auch einen Test durchgeführt, und das hat keine wirkliche Bedeutung für die Art, wie diese Methoden genannt werden, widergespiegelt.
Also bitte, anstatt mich dafür zu beschuldigen, dass ich diese Frage gestellt und mich zu Javadoc geleitet habe, versuche etwas zu versuchen, die wahre Bedeutung hinter ihnen zu erklären. Danke für deine Unterstützung.
Arrays hinzufügen:
//primitive
System.out.println(int.class.getName());
System.out.println(int.class.getCanonicalName());
System.out.println(int.class.getSimpleName());
System.out.println();
//class
System.out.println(String.class.getName());
System.out.println(String.class.getCanonicalName());
System.out.println(String.class.getSimpleName());
System.out.println();
//inner class
System.out.println(HashMap.SimpleEntry.class.getName());
System.out.println(HashMap.SimpleEntry.class.getCanonicalName());
System.out.println(HashMap.SimpleEntry.class.getSimpleName());
System.out.println();
//anonymous inner class
System.out.println(new Serializable(){}.getClass().getName());
System.out.println(new Serializable(){}.getClass().getCanonicalName());
System.out.println(new Serializable(){}.getClass().getSimpleName());
System.out.println();
{
//primitive Array
int demo[] = new int[5];
Class<? extends int[]> clzz = demo.getClass();
System.out.println(clzz.getName());
System.out.println(clzz.getCanonicalName());
System.out.println(clzz.getSimpleName());
}
System.out.println();
{
//Object Array
Integer demo[] = new Integer[5];
Class<? extends Integer[]> clzz = demo.getClass();
System.out.println(clzz.getName());
System.out.println(clzz.getCanonicalName());
System.out.println(clzz.getSimpleName());
}
Fügt Nick Holts Antwort hinzu:
[I
int[]
int[]
[Ljava.lang.Integer;
java.lang.Integer[]
Integer[]
Dies ist das beste Dokument, das ich gefunden habe und getName (), getSimpleName (), getCanonicalName () beschreibt.
// Primitive type
int.class.getName(); // -> int
int.class.getCanonicalName(); // -> int
int.class.getSimpleName(); // -> int
// Standard class
Integer.class.getName(); // -> java.lang.Integer
Integer.class.getCanonicalName(); // -> java.lang.Integer
Integer.class.getSimpleName(); // -> Integer
// Inner class
Map.Entry.class.getName(); // -> java.util.Map$Entry
Map.Entry.class.getCanonicalName(); // -> java.util.Map.Entry
Map.Entry.class.getSimpleName(); // -> Entry
// Anonymous inner class
Class<?> anonymousInnerClass = new Cloneable() {}.getClass();
anonymousInnerClass.getName(); // -> somepackage.SomeClass$1
anonymousInnerClass.getCanonicalName(); // -> null
anonymousInnerClass.getSimpleName(); // -> // An empty string
// Array of primitives
Class<?> primitiveArrayClass = new int[0].getClass();
primitiveArrayClass.getName(); // -> [I
primitiveArrayClass.getCanonicalName(); // -> int[]
primitiveArrayClass.getSimpleName(); // -> int[]
// Array of objects
Class<?> objectArrayClass = new Integer[0].getClass();
objectArrayClass.getName(); // -> [Ljava.lang.Integer;
objectArrayClass.getCanonicalName(); // -> java.lang.Integer[]
objectArrayClass.getSimpleName(); // -> Integer[]
Ich war auch von der Vielzahl unterschiedlicher Benennungsschemata verwirrt und wollte gerade meine eigene Frage dazu stellen und beantworten, als ich diese Frage hier fand. Ich denke, meine Ergebnisse passen gut und ergänzen, was bereits hier ist. Ich konzentriere mich auf Dokumentationen zu den verschiedenen Begriffen und füge weitere verwandte Begriffe hinzu, die an anderen Stellen vorkommen könnten.
Betrachten Sie das folgende Beispiel:
package a.b;
class C {
static class D extends C {
}
D d;
D[] ds;
}
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$
wenn Sie es so schreiben, da$
ein gültiger Teil eines Bezeichners ist.Nach dem JLS-Abschnitt 6.7 wären sowohl
abCD
als auchabCDDD
vollständig qualifizierte Namen , aber nurabCD
wäre der kanonische Name vonD
Jeder kanonische Name ist also ein vollständig qualifizierter Name, aber der Confrees ist nicht immer wahr.Class.getCanonicalName()
gibt den kanonischen Namen odernull
.Class.getName()
ist dokumentiert, um den binären Namen zurückzugeben , wie in JLS Abschnitt 13.1 angegeben . In diesem Fall gibt esabC$D
fürD
und[La.bC$D;
fürD[]
.Diese Antwort zeigt, dass es für zwei Klassen, die von demselben Klassenladeprogramm geladen werden, möglich ist, denselben kanonischen Namen, aber unterschiedliche Binärnamen zu haben . Kein Name ist ausreichend, 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ären Namen haben, wissen Sie nicht, welche
$
als Trennzeichen eingeführt wurden und welche Teil eines einfachen Namens waren.Anonyme Klassen und lokale Klassen haben keine vollqualifizierten Namen , haben aber immer noch einen binären Namen . Dasselbe gilt für Klassen, die in solchen Klassen verschachtelt sind. Jede Klasse hat einen binären Namen.
Das Ausführen von
javap -v -private
aufa/b/C.class
zeigt, dass der Bytecode auf den Typ vond
alsLa/b/C$D;
verweistLa/b/C$D;
und die der Anordnungds
als[La/b/C$D;
. Diese Deskriptoren werden in JVMS Abschnitt 4.3 angegeben .Der Klassenname
a/b/C$D
der in diesen beiden Deskriptoren verwendet wird, erhält man durch Ersetzen.
durch/
in dem binären Namen. Die JVM-Spezifikation nennt dies scheinbar die interne Form des binären Namens . JVMS Abschnitt 4.2.1 beschreibt es und gibt an, dass der Unterschied zum binären Namen aus historischen Gründen sei.Der Dateiname einer Klasse in einem der typischen dateibasierten Klassenladeprogramme erhält man, wenn Sie das
/
in der internen Form des Binärnamens als Verzeichnistrennzeichen interpretieren und die Dateinamenerweiterung.class
an diese Datei anhängen. Es ist relativ zu dem Klassenpfad aufgelöst, der von dem fraglichen Klassenlader verwendet wird.
Lokale Klassen, Lambdas und die toString()
-Methode toString()
, um die vorherigen zwei Antworten zu vervollständigen. Außerdem füge ich Arrays von Lambdas und Arrays von anonymen Klassen hinzu (die in der Praxis keinen Sinn ergeben):
package com.example;
public final class TestClassNames {
private static void showClass(Class<?> c) {
System.out.println("getName(): " + c.getName());
System.out.println("getCanonicalName(): " + c.getCanonicalName());
System.out.println("getSimpleName(): " + c.getSimpleName());
System.out.println("toString(): " + c.toString());
System.out.println();
}
private static void x(Runnable r) {
showClass(r.getClass());
showClass(java.lang.reflect.Array.newInstance(r.getClass(), 1).getClass()); // Obtains an array class of a lambda base type.
}
public static class NestedClass {}
public class InnerClass {}
public static void main(String[] args) {
class LocalClass {}
showClass(void.class);
showClass(int.class);
showClass(String.class);
showClass(Runnable.class);
showClass(SomeEnum.class);
showClass(SomeAnnotation.class);
showClass(int[].class);
showClass(String[].class);
showClass(NestedClass.class);
showClass(InnerClass.class);
showClass(LocalClass.class);
showClass(LocalClass[].class);
Object anonymous = new java.io.Serializable() {};
showClass(anonymous.getClass());
showClass(java.lang.reflect.Array.newInstance(anonymous.getClass(), 1).getClass()); // Obtains an array class of an anonymous base type.
x(() -> {});
}
}
enum SomeEnum {
BLUE, YELLOW, RED;
}
@interface SomeAnnotation {}
Dies ist die vollständige Ausgabe:
getName(): void
getCanonicalName(): void
getSimpleName(): void
toString(): void
getName(): int
getCanonicalName(): int
getSimpleName(): int
toString(): int
getName(): java.lang.String
getCanonicalName(): java.lang.String
getSimpleName(): String
toString(): class java.lang.String
getName(): java.lang.Runnable
getCanonicalName(): java.lang.Runnable
getSimpleName(): Runnable
toString(): interface java.lang.Runnable
getName(): com.example.SomeEnum
getCanonicalName(): com.example.SomeEnum
getSimpleName(): SomeEnum
toString(): class com.example.SomeEnum
getName(): com.example.SomeAnnotation
getCanonicalName(): com.example.SomeAnnotation
getSimpleName(): SomeAnnotation
toString(): interface com.example.SomeAnnotation
getName(): [I
getCanonicalName(): int[]
getSimpleName(): int[]
toString(): class [I
getName(): [Ljava.lang.String;
getCanonicalName(): java.lang.String[]
getSimpleName(): String[]
toString(): class [Ljava.lang.String;
getName(): com.example.TestClassNames$NestedClass
getCanonicalName(): com.example.TestClassNames.NestedClass
getSimpleName(): NestedClass
toString(): class com.example.TestClassNames$NestedClass
getName(): com.example.TestClassNames$InnerClass
getCanonicalName(): com.example.TestClassNames.InnerClass
getSimpleName(): InnerClass
toString(): class com.example.TestClassNames$InnerClass
getName(): com.example.TestClassNames$1LocalClass
getCanonicalName(): null
getSimpleName(): LocalClass
toString(): class com.example.TestClassNames$1LocalClass
getName(): [Lcom.example.TestClassNames$1LocalClass;
getCanonicalName(): null
getSimpleName(): LocalClass[]
toString(): class [Lcom.example.TestClassNames$1LocalClass;
getName(): com.example.TestClassNames$1
getCanonicalName(): null
getSimpleName():
toString(): class com.example.TestClassNames$1
getName(): [Lcom.example.TestClassNames$1;
getCanonicalName(): null
getSimpleName(): []
toString(): class [Lcom.example.TestClassNames$1;
getName(): com.example.TestClassNames$$Lambda$1/1175962212
getCanonicalName(): com.example.TestClassNames$$Lambda$1/1175962212
getSimpleName(): TestClassNames$$Lambda$1/1175962212
toString(): class com.example.TestClassNames$$Lambda$1/1175962212
getName(): [Lcom.example.TestClassNames$$Lambda$1;
getCanonicalName(): com.example.TestClassNames$$Lambda$1/1175962212[]
getSimpleName(): TestClassNames$$Lambda$1/1175962212[]
toString(): class [Lcom.example.TestClassNames$$Lambda$1;
Also, hier sind die Regeln. Lassen Sie uns zuerst mit primitiven Typen und void
:
- Wenn das Klassenobjekt einen primitiven Typ oder
void
, geben alle vier Methoden einfach ihren Namen zurück.
Jetzt die Regeln für die Methode getName()
:
- Jede Nicht-Lambda und Nicht-Array-Klasse oder Schnittstelle (dh oberste Ebene, verschachtelte, innere, lokale und anonyme) hat einen Namen (der von
getName()
), das ist der Paketname, gefolgt von einem Punkt (falls vorhanden) ist ein Paket), gefolgt vom Namen der vom Compiler generierten Klassendatei (ohne das 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 in seinem Klassendateinamen mindestens ein$
generieren. Beachten Sie, dass der Klassenname für anonyme Klassen mit einem Dollarzeichen gefolgt von einer Zahl endet. - Lambda-Klassennamen sind im Allgemeinen unvorhersehbar, und Sie sollten sie sowieso nicht interessieren. Genau, ihr Name ist der Name der umschließenden Klasse, gefolgt von
$$Lambda$
, gefolgt von einer Zahl, gefolgt von einem Schrägstrich, gefolgt von einer anderen Zahl. - Der Klassendeskriptor der Grundelemente ist
Z
fürboolean
,B
fürbyte
,S
fürshort
,C
fürchar
,I
fürint
,J
fürlong
,F
fürfloat
undD
fürdouble
. Für Nicht-Array-Klassen und -Schnittstellen ist der KlassendeskriptorL
gefolgt von dem, wasgetName()
gefolgt von;
. Für Array-Klassen lautet der Klassendeskriptor[
gefolgt vom Klassendeskriptor des Komponententyps (der selbst eine andere Array-Klasse sein kann). - Für Array-Klassen gibt die Methode
getName()
ihren Klassendeskriptor zurück. Diese Regel scheint nur für Array-Klassen zu versagen, deren Komponententyp ein Lambda ist (was möglicherweise ein Fehler ist), aber hoffentlich sollte das sowieso nichts ausmachen, da es sogar keinen Sinn gibt, Array-Klassen zu verwenden, deren Komponententyp ein Lambda ist.
Nun, die toString()
Methode:
- Wenn die Klasseninstanz eine Schnittstelle darstellt (oder eine Annotation, bei der es sich um eine spezielle Schnittstelle handelt), gibt
toString()
"interface " + getName()
. Wenn es ein Primitiv ist, gibt es einfachgetName()
. Wenn es etwas anderes ist (ein Klassentyp, auch wenn es ein ziemlich seltsamer ist), gibt es"class " + getName()
.
Die Methode getCanonicalName()
:
- Für Top-Level-Klassen und -Schnittstellen gibt die
getCanonicalName()
-Methode genau das zurück, was diegetName()
-Methode zurückgibt. - Die Methode
getCanonicalName()
gibtnull
für anonyme oder lokale Klassen und für Arrayklassen dieser Klassen zurück. - Für innere und verschachtelte Klassen und Interfaces gibt die Methode
getCanonicalName()
zurück, was die MethodegetName()
die vom Compiler eingeführten Dollarzeichen durch Punkte ersetzen würde. - Für Array-Klassen gibt die Methode
getCanonicalName()
null
wenn der kanonische Name des Komponententypsnull
. Andernfalls wird der kanonische Name des Komponententyps gefolgt von[]
.
Die getSimpleName()
Methode:
- Für Klassen der obersten Ebene, verschachtelte, innere und lokale Klassen gibt
getSimpleName()
den Namen der Klasse zurück, die in der Quelldatei geschrieben wurde. - Für anonyme Klassen gibt
getSimpleName()
einen leerenString
. - Bei Lambda-Klassen gibt
getSimpleName()
nur das zurück, wasgetName()
ohne den Paketnamen zurückgeben würde. Das macht nicht viel Sinn und sieht für mich wie ein Fehler aus, aber es hat keinen Sinn,getSimpleName()
für eine Lambda-KlassegetSimpleName()
. - Für Array-Klassen gibt die Methode
getSimpleName()
den einfachen Namen der Komponentenklasse gefolgt von[]
. Dies hat den seltsamen Nebeneffekt, dass Array-Klassen, deren Komponententyp eine anonyme Klasse ist, nur[]
als einfache Namen haben.
public void printReflectionClassNames(){
StringBuffer buffer = new StringBuffer();
Class clazz= buffer.getClass();
System.out.println("Reflection on String Buffer Class");
System.out.println("Name: "+clazz.getName());
System.out.println("Simple Name: "+clazz.getSimpleName());
System.out.println("Canonical Name: "+clazz.getCanonicalName());
System.out.println("Type Name: "+clazz.getTypeName());
}
outputs:
Reflection on String Buffer Class
Name: java.lang.StringBuffer
Simple Name: StringBuffer
Canonical Name: java.lang.StringBuffer
Type Name: java.lang.StringBuffer