Adicionando classes locais, lambdas e o toString()
método para concluir as duas respostas anteriores. Além disso, adiciono matrizes de lambdas e matrizes de classes anônimas (que, na prática, não fazem nenhum sentido):
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 {}
Esta é a saída completa:
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;
Então, aqui estão as regras. Primeiro, vamos começar com tipos primitivos e void
:
- Se o objeto de classe representa um tipo primitivo ou
void
, todos os quatro métodos simplesmente retornam seu nome.
Agora as regras para o getName()
método:
- Toda classe ou interface que não seja lambda e não array (ou seja, nível superior, aninhado, interno, local e anônimo) tem um nome (retornado por
getName()
) que é o nome do pacote seguido por um ponto (se houver um pacote ), seguido pelo nome do seu arquivo de classe, conforme gerado pelo compilador (sem o sufixo .class
). Se não houver pacote, é simplesmente o nome do arquivo de classe. Se a classe for uma classe interna, aninhada, local ou anônima, o compilador deve gerar pelo menos um $
em seu nome de arquivo de classe. Observe que, para classes anônimas, o nome da classe terminaria com um cifrão seguido de um número.
- Os nomes das classes Lambda geralmente são imprevisíveis e você não deve se preocupar com eles. Exatamente, o nome deles é o nome da classe envolvente, seguido por
$$Lambda$
, seguido por um número, seguido por uma barra, seguido por outro número.
- O descritor de classe das primitivas é
Z
para boolean
, B
para byte
, S
para short
, C
para char
, I
para int
, J
para long
, F
para float
e D
para double
. Para classes e interfaces que não são de matriz, o descritor de classe é L
seguido pelo que é fornecido por getName()
seguido por ;
. Para classes de matriz, o descritor de classe é [
seguido pelo descritor de classe do tipo de componente (que pode ser outra classe de matriz).
- Para classes de matriz, o
getName()
método retorna seu descritor de classe. Essa regra parece falhar apenas para classes de matriz cujo tipo de componente é um lambda (que possivelmente é um bug), mas espero que isso não importe de qualquer maneira, porque não faz sentido nem mesmo a existência de classes de matriz cujo tipo de componente é um lambda.
Agora, o toString()
método:
- Se a instância da classe representar uma interface (ou uma anotação, que é um tipo especial de interface), os
toString()
retornos "interface " + getName()
. Se é um primitivo, ele retorna simplesmente getName()
. Se for outra coisa (um tipo de classe, mesmo que seja bem estranho), ele retornará "class " + getName()
.
O getCanonicalName()
método:
- Para classes e interfaces de nível superior, o
getCanonicalName()
método retorna exatamente o que o getName()
método retorna.
- O
getCanonicalName()
método retorna null
para classes anônimas ou locais e para classes de matriz dessas.
- Para classes e interfaces internas e aninhadas, o
getCanonicalName()
método retorna o que o getName()
método substituiria os cifrões introduzidos pelo compilador por pontos.
- Para as classes de matriz, o
getCanonicalName()
método retorna null
se o nome canónica do tipo de componente é null
. Caso contrário, ele retornará o nome canônico do tipo de componente seguido por []
.
O getSimpleName()
método:
- Para classes de nível superior, aninhadas, internas e locais,
getSimpleName()
retorna o nome da classe conforme escrito no arquivo de origem.
- Para classes anônimas, o
getSimpleName()
retorno é vazio String
.
- Para classes lambda, o
getSimpleName()
just retorna o getName()
que retornaria sem o nome do pacote. Isso não faz muito sentido e parece um bug para mim, mas não faz sentido chamar getSimpleName()
uma classe lambda para começar.
- Para classes de matriz, o
getSimpleName()
método retorna o nome simples da classe de componente seguido por []
. Isso tem o efeito colateral engraçado / estranho de que as classes de matriz cujo tipo de componente é uma classe anônima têm apenas []
seus nomes simples.