Aggiunta di classi locali, lambda e toString()
metodo per completare le due risposte precedenti. Inoltre, aggiungo array di lambda e array di classi anonime (che in pratica non hanno alcun senso):
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 {}
Questo è l'output completo:
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;
Quindi, ecco le regole. Innanzitutto, iniziamo con tipi primitivi e void
:
- Se l'oggetto class rappresenta un tipo primitivo o
void
, tutti e quattro i metodi restituiscono semplicemente il suo nome.
Ora le regole per il getName()
metodo:
- Ogni classe o interfaccia non lambda e non array (ad esempio, di livello superiore, nidificato, interno, locale e anonimo) ha un nome (che viene restituito da
getName()
) che è il nome del pacchetto seguito da un punto (se esiste un pacchetto ), seguito dal nome del suo file di classe generato dal compilatore (senza il suffisso .class
). Se non esiste un pacchetto, è semplicemente il nome del file di classe. Se la classe è una classe interna, nidificata, locale o anonima, il compilatore dovrebbe generarne almeno una $
nel nome del suo file di classe. Nota che per le classi anonime, il nome della classe terminerebbe con un segno di dollaro seguito da un numero.
- I nomi delle classi Lambda sono generalmente imprevedibili e non dovresti preoccupartene comunque. Esatto, il loro nome è il nome della classe allegata, seguito da
$$Lambda$
, seguito da un numero, seguito da una barra, seguito da un altro numero.
- Il descrittore di classe dei primitivi è
Z
per boolean
, B
per byte
, S
per short
, C
per char
, I
per int
, J
per long
, F
per float
e D
per double
. Per le classi e le interfacce non array il descrittore di classe è L
seguito da ciò che è dato da getName()
seguito da ;
. Per le classi di array, il descrittore di classe è [
seguito dal descrittore di classe del tipo di componente (che può essere esso stesso un'altra classe di array).
- Per le classi di array, il
getName()
metodo restituisce il descrittore di classe. Questa regola sembra fallire solo per le classi di array il cui tipo di componente è un lambda (che probabilmente è un bug), ma si spera che questo non dovrebbe importare comunque perché non ha senso nemmeno l'esistenza delle classi di array il cui tipo di componente è un lambda.
Ora, il toString()
metodo:
- Se l'istanza della classe rappresenta un'interfaccia (o un'annotazione, che è un tipo speciale di interfaccia), i
toString()
ritorni"interface " + getName()
. Se è un primitivo, ritorna semplicemente getName()
. Se è qualcos'altro (un tipo di classe, anche se piuttosto strano), ritorna "class " + getName()
.
Il getCanonicalName()
metodo:
- Per le classi e le interfacce di livello superiore, il
getCanonicalName()
metodo restituisce esattamente ciò getName()
che restituisce il metodo.
- Il
getCanonicalName()
metodo ritorna null
per le classi anonime o locali e per le classi di array di quelle.
- Per le classi e le interfacce interne e nidificate, il
getCanonicalName()
metodo restituisce ciò che il getName()
metodo sostituirebbe i segni del dollaro introdotti dal compilatore con punti.
- Per le classi di array, il
getCanonicalName()
metodo restituisce null
se il nome canonico del tipo di componente è null
. Altrimenti, restituisce il nome canonico del tipo di componente seguito da[]
.
Il getSimpleName()
metodo:
- Per le classi di livello superiore, nidificate, interne e locali, il
getSimpleName()
restituisce il nome della classe come scritto nel file di origine.
- Per le classi anonime il
getSimpleName()
restituisce un vuoto String
.
- Per le classi lambda il
getSimpleName()
giusto restituisce ciò che ilgetName()
verrebbe restituito senza il nome del pacchetto. Questo non ha molto senso e mi sembra un bug, ma non ha senso invocare getSimpleName()
una classe lambda per cominciare.
- Per le classi di array il
getSimpleName()
metodo restituisce il nome semplice della classe del componente seguito da []
. Questo ha il divertente / strano effetto collaterale che le classi di array il cui tipo di componente è una classe anonima hanno []
i loro semplici nomi.