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.

https://javahowtodoit.wordpress.com/2014/09/09/java-lang-class-what-is-the-difference-between-class-getname-class-getcanonicalname-and-class-getsimplename/

// 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 ist D 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 auch abCDDD vollständig qualifizierte Namen , aber nur abCD wäre der kanonische Name von D Jeder kanonische Name ist also ein vollständig qualifizierter Name, aber der Confrees ist nicht immer wahr. Class.getCanonicalName() gibt den kanonischen Namen oder null .

  • Class.getName() ist dokumentiert, um den binären Namen zurückzugeben , wie in JLS Abschnitt 13.1 angegeben . In diesem Fall gibt es abC$D für D und [La.bC$D; für D[] .

  • 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 auf a/b/C.class zeigt, dass der Bytecode auf den Typ von d als La/b/C$D; verweist La/b/C$D; und die der Anordnung ds 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 :

  1. 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() :

  1. 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.
  2. 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.
  3. Der Klassendeskriptor der Grundelemente ist Z für boolean , B für byte , S für short , C für char , I für int , J für long , F für float und D für double . Für Nicht-Array-Klassen und -Schnittstellen ist der Klassendeskriptor L gefolgt von dem, was getName() gefolgt von ; . Für Array-Klassen lautet der Klassendeskriptor [ gefolgt vom Klassendeskriptor des Komponententyps (der selbst eine andere Array-Klasse sein kann).
  4. 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:

  1. 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 einfach getName() . Wenn es etwas anderes ist (ein Klassentyp, auch wenn es ein ziemlich seltsamer ist), gibt es "class " + getName() .

Die Methode getCanonicalName() :

  1. Für Top-Level-Klassen und -Schnittstellen gibt die getCanonicalName() -Methode genau das zurück, was die getName() -Methode zurückgibt.
  2. Die Methode getCanonicalName() gibt null für anonyme oder lokale Klassen und für Arrayklassen dieser Klassen zurück.
  3. Für innere und verschachtelte Klassen und Interfaces gibt die Methode getCanonicalName() zurück, was die Methode getName() die vom Compiler eingeführten Dollarzeichen durch Punkte ersetzen würde.
  4. Für Array-Klassen gibt die Methode getCanonicalName() null wenn der kanonische Name des Komponententyps null . Andernfalls wird der kanonische Name des Komponententyps gefolgt von [] .

Die getSimpleName() Methode:

  1. 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.
  2. Für anonyme Klassen gibt getSimpleName() einen leeren String .
  3. Bei Lambda-Klassen gibt getSimpleName() nur das zurück, was getName() 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-Klasse getSimpleName() .
  4. 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




java