Agregar clases locales, lambdas y el toString()
método para completar las dos respuestas anteriores. Además, agrego matrices de lambdas y matrices de clases anónimas (que no tienen ningún sentido en la práctica):
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 {}
Este es el resultado 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;
Entonces, aquí están las reglas. Primero, comencemos con los tipos primitivos y void
:
- Si el objeto de clase representa un tipo primitivo o
void
, los cuatro métodos simplemente devuelven su nombre.
Ahora las reglas para el getName()
método:
- Cada clase o interfaz que no sea lambda ni matriz (es decir, de nivel superior, anidada, interna, local y anónima) tiene un nombre (que es devuelto por
getName()
) que es el nombre del paquete seguido de un punto (si hay un paquete ), seguido del nombre de su archivo de clase generado por el compilador (sin el sufijo .class
). Si no hay paquete, es simplemente el nombre del archivo de clase. Si la clase es una clase interna, anidada, local o anónima, el compilador debe generar al menos una $
en su nombre de archivo de clase. Tenga en cuenta que para las clases anónimas, el nombre de la clase terminaría con un signo de dólar seguido de un número.
- Los nombres de clase de Lambda son generalmente impredecibles, y de todos modos no debería preocuparse por ellos. Exactamente, su nombre es el nombre de la clase adjunta, seguido de
$$Lambda$
, seguido de un número, seguido de una barra inclinada, seguido de otro número.
- El descriptor de clase de las primitivas son
Z
para boolean
, B
para byte
, S
para short
, C
para char
, I
para int
, J
para long
, F
para float
y D
para double
. Para las clases y las interfaces que no son matrices, el descriptor de la clase es L
seguido por lo que viene getName()
seguido por ;
. Para las clases de matriz, el descriptor de clase es [
seguido por el descriptor de clase del tipo de componente (que puede ser otra clase de matriz).
- Para las clases de matriz, el
getName()
método devuelve su descriptor de clase. Esta regla parece fallar solo para las clases de matriz cuyo tipo de componente es una lambda (que posiblemente sea un error), pero con suerte esto no debería importar de todos modos porque no tiene sentido incluso la existencia de clases de matriz cuyo tipo de componente es una lambda.
Ahora, el toString()
método:
- Si la instancia de clase representa una interfaz (o una anotación, que es un tipo especial de interfaz), los
toString()
retornos "interface " + getName()
. Si es un primitivo, vuelve simplemente getName()
. Si es algo más (un tipo de clase, incluso si es bastante raro), regresa "class " + getName()
.
El getCanonicalName()
método:
- Para las clases e interfaces de nivel superior, el
getCanonicalName()
método devuelve exactamente lo getName()
que devuelve el método.
- El
getCanonicalName()
método devuelve null
para clases anónimas o locales y para clases de matriz de esos.
- Para las clases e interfaces internas y anidadas, el
getCanonicalName()
método devuelve lo getName()
que reemplazaría los signos de dólar introducidos por el compilador por puntos.
- Para las clases de matriz, el
getCanonicalName()
método devuelve null
si el nombre canónico del tipo de componente es null
. De lo contrario, devuelve el nombre canónico del tipo de componente seguido de []
.
El getSimpleName()
método:
- Para las clases de nivel superior, anidadas, internas y locales,
getSimpleName()
devuelve el nombre de la clase tal como está escrito en el archivo fuente.
- Para clases anónimas,
getSimpleName()
devuelve un vacío String
.
- Para las clases lambda, el
getSimpleName()
just devuelve lo getName()
que devolvería sin el nombre del paquete. Esto no tiene mucho sentido y parece un error para mí, pero no tiene sentido llamar getSimpleName()
a una clase lambda para empezar.
- Para las clases de matriz, el
getSimpleName()
método devuelve el nombre simple de la clase de componente seguido de []
. Esto tiene el efecto secundario divertido / extraño que las clases de matriz cuyo tipo de componente es una clase anónima tienen []
como nombres simples.