Quelle est la différence entre le nom canonique, le nom simple et le nom de classe dans la classe Java?

En Java, quelle est la différence entre ces éléments:

Object o1 = .... o1.getClass().getSimpleName(); o1.getClass().getName(); o1.getClass().getCanonicalName(); 

J’ai vérifié le Javadoc plusieurs fois et pourtant cela ne l’explique jamais bien. J’ai également effectué un test qui ne reflétait pas réellement la manière dont ces méthodes sont appelées.

Si vous n’êtes pas sûr de quelque chose, essayez d’abord d’écrire un test.

J’ai fait ça:

 //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(Ssortingng.class.getName()); System.out.println(Ssortingng.class.getCanonicalName()); System.out.println(Ssortingng.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()); 

Impressions:

 int
 int
 int

 java.lang.Ssortingng
 java.lang.Ssortingng
 Chaîne

 java.util.AbstractMap $ SimpleEntry
 java.util.AbstractMap.SimpleEntry
 SimpleEntry

 Nom de classeTest $ 1
 nul

Il y a une ligne vide dans le dernier bloc où getSimpleName renvoie une chaîne vide.

Le résultat est que:

  • le nom est le nom que vous utiliseriez pour charger dynamicment la classe avec, par exemple, un appel à Class.forName avec le ClassLoader par défaut.
  • le nom canonique est le nom qui serait utilisé dans une instruction import et identifie de manière unique la classe. Peut être utile lors des opérations de toSsortingng ou de journalisation.
  • le nom simple identifie librement la classe, encore une fois, peut être utile lors des opérations de toSsortingng ou de journalisation, mais il n’est pas garanti qu’il soit unique.

En plus des observations de Nick Holt, j’ai couru quelques cas pour le type de données Array :

 //primitive Array int demo[] = new int[5]; Class 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 clzz = demo.getClass(); System.out.println(clzz.getName()); System.out.println(clzz.getCanonicalName()); System.out.println(clzz.getSimpleName()); 

Les extraits de code ci-dessus s’impriment:

 [I int[] int[] [Ljava.lang.Integer; java.lang.Integer[] Integer[] 

Ajouter des classes locales, lambdas et la toSsortingng() pour compléter les deux réponses précédentes. De plus, j’ajoute des tableaux de lambda et des tableaux de classes anonymes (qui n’ont aucun sens dans la pratique):

 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("toSsortingng(): " + c.toSsortingng()); 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(Ssortingng[] args) { class LocalClass {} showClass(void.class); showClass(int.class); showClass(Ssortingng.class); showClass(Runnable.class); showClass(SomeEnum.class); showClass(SomeAnnotation.class); showClass(int[].class); showClass(Ssortingng[].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 {} 

Ceci est la sortie complète:

 getName(): void getCanonicalName(): void getSimpleName(): void toSsortingng(): void getName(): int getCanonicalName(): int getSimpleName(): int toSsortingng(): int getName(): java.lang.Ssortingng getCanonicalName(): java.lang.Ssortingng getSimpleName(): Ssortingng toSsortingng(): class java.lang.Ssortingng getName(): java.lang.Runnable getCanonicalName(): java.lang.Runnable getSimpleName(): Runnable toSsortingng(): interface java.lang.Runnable getName(): com.example.SomeEnum getCanonicalName(): com.example.SomeEnum getSimpleName(): SomeEnum toSsortingng(): class com.example.SomeEnum getName(): com.example.SomeAnnotation getCanonicalName(): com.example.SomeAnnotation getSimpleName(): SomeAnnotation toSsortingng(): interface com.example.SomeAnnotation getName(): [I getCanonicalName(): int[] getSimpleName(): int[] toSsortingng(): class [I getName(): [Ljava.lang.Ssortingng; getCanonicalName(): java.lang.Ssortingng[] getSimpleName(): Ssortingng[] toSsortingng(): class [Ljava.lang.Ssortingng; getName(): com.example.TestClassNames$NestedClass getCanonicalName(): com.example.TestClassNames.NestedClass getSimpleName(): NestedClass toSsortingng(): class com.example.TestClassNames$NestedClass getName(): com.example.TestClassNames$InnerClass getCanonicalName(): com.example.TestClassNames.InnerClass getSimpleName(): InnerClass toSsortingng(): class com.example.TestClassNames$InnerClass getName(): com.example.TestClassNames$1LocalClass getCanonicalName(): null getSimpleName(): LocalClass toSsortingng(): class com.example.TestClassNames$1LocalClass getName(): [Lcom.example.TestClassNames$1LocalClass; getCanonicalName(): null getSimpleName(): LocalClass[] toSsortingng(): class [Lcom.example.TestClassNames$1LocalClass; getName(): com.example.TestClassNames$1 getCanonicalName(): null getSimpleName(): toSsortingng(): class com.example.TestClassNames$1 getName(): [Lcom.example.TestClassNames$1; getCanonicalName(): null getSimpleName(): [] toSsortingng(): class [Lcom.example.TestClassNames$1; getName(): com.example.TestClassNames$$Lambda$1/1175962212 getCanonicalName(): com.example.TestClassNames$$Lambda$1/1175962212 getSimpleName(): TestClassNames$$Lambda$1/1175962212 toSsortingng(): 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[] toSsortingng(): class [Lcom.example.TestClassNames$$Lambda$1; 

Alors, voici les règles. Tout d’abord, commençons par les types primitifs et void :

  1. Si l’object de classe représente un type primitif ou void , toutes les quatre méthodes renvoient simplement son nom.

Maintenant, les règles pour la méthode getName() :

  1. Chaque classe ou interface non lambda et non-tableau (c.-à-d. Niveau supérieur, nested, interne, local et anonyme) a un nom (qui est retourné par getName() ) qui est le nom du paquet suivi d’un point est un package), suivi du nom de son fichier de classe tel que généré par le compilateur (sans le suffixe .class ). S’il n’y a pas de paquet, c’est simplement le nom du fichier de classe. Si la classe est une classe interne, nestede, locale ou anonyme, le compilateur doit générer au moins un $ dans son nom de fichier de classe. Notez que pour les classes anonymes, le nom de la classe se termine par un signe dollar suivi d’un nombre.
  2. Les noms de classe Lambda sont généralement imprévisibles et vous ne devriez pas vous en soucier. Exactement, leur nom est le nom de la classe englobante, suivi de $$Lambda$ , suivi d’un nombre suivi d’une barre oblique, suivi d’un autre numéro.
  3. Les descripteurs de classe des primitives sont Z pour boolean , B pour byte , S pour short , C pour char , I pour int , J pour long , F pour float et D pour double . Pour les classes et interfaces non-tableau, le descripteur de classe est L suivi de ce qui est donné par getName() suivi de ; . Pour les classes de tableau, le descripteur de classe est [ suivi du descripteur de classe du type de composant (qui peut être lui-même une autre classe de tableau).
  4. Pour les classes de tableau, la méthode getName() renvoie son descripteur de classe. Cette règle semble échouer uniquement pour les classes de tableaux dont le type de composant est un lambda (ce qui est peut-être un bogue), mais cela ne devrait pas avoir d’importance, car il n’ya même pas de classes de composants dont le type de composant est un lambda.

Maintenant, la toSsortingng() :

  1. Si l’instance de classe représente une interface (ou une annotation, qui est un type spécial d’interface), le toSsortingng() renvoie "interface " + getName() . S’il s’agit d’une primitive, elle renvoie simplement getName() . Si c’est autre chose (un type de classe, même si c’est un peu bizarre), il retourne "class " + getName() .

La méthode getCanonicalName() :

  1. Pour les classes et interfaces de niveau supérieur, la méthode getCanonicalName() renvoie simplement le retour de la méthode getName() .
  2. La méthode getCanonicalName() renvoie null pour les classes anonymes ou locales et pour les classes de tableau de celles-ci.
  3. Pour les classes et les interfaces internes et nestedes, la méthode getCanonicalName() renvoie ce que la méthode getName() remplacerait par des points.
  4. Pour les classes de tableau, la méthode getCanonicalName() renvoie null si le nom canonique du type de composant est null . Sinon, il renvoie le nom canonique du type de composant suivi de [] .

La méthode getSimpleName() :

  1. Pour les classes de premier niveau, nestedes, internes et locales, getSimpleName() renvoie le nom de la classe tel qu’il est écrit dans le fichier source.
  2. Pour les classes anonymes, getSimpleName() renvoie une Ssortingng vide.
  3. Pour les classes lambda, getSimpleName() renvoie simplement ce que getName() renverrait sans le nom du package. Cela n’a pas beaucoup de sens et ressemble à un bogue pour moi, mais il est inutile d’appeler getSimpleName() sur une classe lambda pour commencer.
  4. Pour les classes de tableaux, la méthode getSimpleName() renvoie le nom simple de la classe de composants suivi de [] . Cela a l’effet étrange / bizarre que les classes de tableau dont le type de composant est une classe anonyme ont simplement [] comme noms simples.

J’ai été déconcerté par le large éventail de schémas de nommage différents, et j’étais sur le sharepoint poser ma propre question à ce sujet et d’y répondre. Je pense que mes découvertes s’intègrent assez bien et complètent ce qui existe déjà. Mon objective est de rechercher de la documentation sur les différents termes, et d’append des termes plus connexes qui pourraient apparaître ailleurs.

Prenons l’exemple suivant:

 package ab; class C { static class D extends C { } D d; D[] ds; } 
  • Le nom simple de D est D C’est juste la partie que vous avez écrite en déclarant la classe. Les classes anonymes n’ont pas de nom simple. Class.getSimpleName() renvoie ce nom ou la chaîne vide. Il est possible que le nom simple contienne un $ si vous l’écrivez comme ceci, puisque $ est une partie valide d’un identifiant.

  • Selon la section 6.7 de JLS , abCD et abCDDD seraient des noms entièrement qualifiés , mais seul abCD serait le nom canonique de D Ainsi, chaque nom canonique est un nom complet, mais les convergents ne sont pas toujours vrais. Class.getCanonicalName() renverra le nom canonique ou null .

  • Class.getName() est documenté pour renvoyer le nom binary , comme spécifié dans la section 13.1 de JLS . Dans ce cas, il renvoie abC$D pour D et [La.bC$D; pour D[] .

  • Cette réponse montre qu’il est possible que deux classes chargées par le même chargeur de classe aient le même nom canonique mais des noms binarys distincts. Aucun des deux noms ne suffit à déduire de manière fiable l’autre: si vous avez le nom canonique, vous ne savez pas quelles parties du nom sont des packages et lesquelles contiennent des classes. Si vous avez le nom binary, vous ne savez pas quels sont les $ introduits comme séparateurs et ceux qui font partie d’un nom simple.

  • Les classes anonymes et les classes locales n’ont pas de noms complets mais ont toujours un nom binary . La même chose vaut pour les classes nestedes dans de telles classes. Chaque classe a un nom binary.

  • L’exécution de javap -v -private sur a/b/C.class montre que le bytecode fait référence au type de d comme La/b/C$D; et celui du tableau ds comme [La/b/C$D; . Ceux-ci sont appelés descripteurs et ils sont spécifiés dans la section JVMS 4.3 .

  • Le nom de classe a/b/C$D utilisé dans ces deux descripteurs est ce que vous obtenez en remplaçant . par / dans le nom binary. La spécification JVM appelle apparemment cela la forme interne du nom binary . La section 4.2.1 de JVMS le décrit et indique que la différence par rapport au nom binary était pour des raisons historiques.

  • Le nom de fichier d’une classe dans l’un des chargeurs de classes classiques basés sur des noms de fichiers est ce que vous obtenez si vous interprétez le / dans la forme interne du nom binary comme séparateur de répertoire et ajoutez l’extension de nom de fichier .class à celui-ci. Il est résolu par rapport au chemin de classe utilisé par le chargeur de classe en question.

c’est le meilleur document que j’ai trouvé décrivant getName (), getSimpleName (), getCanonicalName ()

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 ssortingng // 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[] 

Il est intéressant de noter que getCanonicalName() et getSimpleName() peuvent getSimpleName() InternalError lorsque le nom de la classe est mal formé. Cela se produit pour certains langages JVM non Java, par exemple Scala.

Considérez ce qui suit (Scala 2.11 sur Java 8):

 scala> case class C() defined class C scala> val c = C() c: C = C() scala> c.getClass.getSimpleName java.lang.InternalError: Malformed class name at java.lang.Class.getSimpleName(Class.java:1330) ... 32 elided scala> c.getClass.getCanonicalName java.lang.InternalError: Malformed class name at java.lang.Class.getSimpleName(Class.java:1330) at java.lang.Class.getCanonicalName(Class.java:1399) ... 32 elided scala> c.getClass.getName res2: Ssortingng = C 

Cela peut être un problème pour les environnements ou environnements mixtes qui chargent dynamicment le bytecode, par exemple les serveurs d’applications et les autres logiciels de plate-forme.

  public void printReflectionClassNames(){ SsortingngBuffer buffer = new SsortingngBuffer(); Class clazz= buffer.getClass(); System.out.println("Reflection on Ssortingng 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 Ssortingng Buffer Class Name: java.lang.SsortingngBuffer Simple Name: SsortingngBuffer Canonical Name: java.lang.SsortingngBuffer Type Name: java.lang.SsortingngBuffer