Ajout de classes locales, de lambdas et de la toString()
méthode pour compléter les deux réponses précédentes. De plus, j'ajoute des tableaux de lambdas et des tableaux de classes anonymes (qui n'ont cependant 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("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 {}
Voici la sortie complète:
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;
Voici donc les règles. Tout d'abord, commençons par les types primitifs et void
:
- Si l'objet classe représente un type primitif ou
void
, les quatre méthodes renvoient simplement son nom.
Maintenant, les règles de la getName()
méthode:
- Chaque classe ou interface non lambda et non tableau (c'est-à-dire de niveau supérieur, imbriqué, interne, local et anonyme) a un nom (qui est renvoyé par
getName()
) qui est le nom du package suivi d'un point (s'il y a 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 package, c'est simplement le nom du fichier de classe. Si la classe est une classe interne, imbriquée, locale ou anonyme, le compilateur doit en générer au moins une $
dans son nom de fichier de classe. Notez que pour les classes anonymes, le nom de la classe se terminerait par un signe dollar suivi d'un nombre.
- Les noms de classe Lambda sont généralement imprévisibles, et vous ne devriez pas vous en soucier de toute façon. 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 nombre.
- Le descripteur de classe des primitives est
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 matricielles, 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).
- Pour les classes de tableaux, la
getName()
méthode renvoie son descripteur de classe. Cette règle semble échouer uniquement pour les classes de tableau dont le type de composant est un lambda (ce qui est peut-être un bogue), mais j'espère que cela ne devrait pas avoir d'importance de toute façon car il n'y a aucun point même sur l'existence de classes de tableau dont le type de composant est un lambda.
Maintenant, la toString()
méthode:
- Si l'instance de classe représente une interface (ou une annotation, qui est un type spécial d'interface), le
toString()
retourne "interface " + getName()
. S'il s'agit d'une primitive, elle revient simplement getName()
. Si c'est autre chose (un type de classe, même s'il est assez bizarre), il revient "class " + getName()
.
La getCanonicalName()
méthode:
- Pour les classes et les interfaces de niveau supérieur, la
getCanonicalName()
méthode renvoie exactement ce qu'elle getName()
renvoie.
- La
getCanonicalName()
méthode renvoie null
pour les classes anonymes ou locales et pour les classes de tableau de celles-ci.
- Pour les classes et interfaces internes et imbriquées, la
getCanonicalName()
méthode renvoie ce que la getName()
méthode remplacerait les signes dollar introduits par le compilateur par des points.
- Pour les classes de tableaux, la
getCanonicalName()
méthode 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 getSimpleName()
méthode:
- Pour les classes de niveau supérieur, imbriquées, internes et locales, le
getSimpleName()
renvoie le nom de la classe tel qu'il est écrit dans le fichier source.
- Pour les classes anonymes, la
getSimpleName()
renvoie un vide String
.
- Pour les classes lambda, le
getSimpleName()
renvoie simplement ce que le getName()
retournerait 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()
une classe lambda pour commencer.
- Pour les classes de tableaux, la
getSimpleName()
méthode renvoie le nom simple de la classe de composants suivi de []
. Cela a pour effet secondaire drôle / bizarre que les classes de tableaux dont le type de composant est une classe anonyme ont tout []
comme leurs noms simples.