una tipos que metodos herencia ejemplos crear constructores como clases clase atributos java

tipos - ¿Cuál es la diferencia entre nombre canónico, nombre simple y nombre de clase en Java Class?



que es una clase en java (7)

En Java, ¿cuál es la diferencia entre estos:

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

He revisado el Javadoc varias veces y, sin embargo, esto nunca lo explica bien. También realicé una prueba y eso no reflejaba ningún significado real detrás de la forma en que se llaman estos métodos.


Además de las observaciones de Nick Holt, corrí algunos casos para el tipo de datos Array :

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

Sobre el fragmento de código se imprime:

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


Agregando clases locales, lambdas y el método toString() para completar las dos respuestas anteriores. Además, agrego arrays de lambdas y arrays de clases anónimas (que no tienen sentido en la práctica, sin embargo):

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 es la salida 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;

Entonces, aquí están las reglas. Primero, comencemos con tipos primitivos y void :

  1. Si el objeto de clase representa un tipo primitivo o void , los cuatro métodos simplemente devuelven su nombre.

Ahora las reglas para el método getName() :

  1. Cada clase o interfaz no lambda y no de 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 existe) es un paquete), seguido del nombre de su archivo de clase como lo genera el compilador (sin el sufijo .class ). Si no hay ningún paquete, es simplemente el nombre del archivo de clase. Si la clase es interna, anidada, local o anónima, el compilador debe generar al menos un $ 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.
  2. Los nombres de las clases Lambda son generalmente impredecibles, y no debería preocuparse por ellos de todos modos. Exactamente, su nombre es el nombre de la clase adjunta, seguido de $$Lambda$ , seguido de un número, seguido de una barra oblicua, seguido de otro número.
  3. El descriptor de clase de las primitivas es 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 e interfaces que no son de matriz, el descriptor de la clase es L seguido de lo que da getName() seguido de ; . Para las clases de matriz, el descriptor de clase es [ seguido del descriptor de clase del tipo de componente (que puede ser en sí mismo otra clase de matriz).
  4. Para las clases de matriz, el método getName() devuelve su descriptor de clase. Esta regla parece fallar solo para las clases de matriz cuyo tipo de componente es lambda (que posiblemente sea un error), pero es de esperar que esto no importe de todos modos porque no tiene sentido ni siquiera la existencia de clases de matriz cuyo tipo de componente sea una lambda.

Ahora, el método toString() :

  1. Si la instancia de la clase representa una interfaz (o una anotación, que es un tipo especial de interfaz), toString() devuelve "interface " + getName() . Si es una primitiva, devuelve simplemente getName() . Si es otra cosa (un tipo de clase, incluso si es bastante extraño), devuelve "class " + getName() .

El método getCanonicalName() :

  1. Para las clases e interfaces de nivel superior, el método getCanonicalName() devuelve lo que devuelve el método getName() .
  2. El método getCanonicalName() devuelve null para las clases anónimas o locales y para las clases de matriz de esas.
  3. Para las clases e interfaces internas y anidadas, el método getCanonicalName() devuelve lo que el método getName() reemplazaría los signos de dólar introducidos por el compilador por puntos.
  4. Para las clases de matriz, el método getCanonicalName() 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 método getSimpleName() :

  1. Para las clases de nivel superior, anidadas, internas y locales, el getSimpleName() devuelve el nombre de la clase como está escrito en el archivo fuente.
  2. Para las clases anónimas, el getSimpleName() devuelve una String vacía.
  3. Para las clases lambda, el getSimpleName() simplemente devuelve lo que el getName() devolvería sin el nombre del paquete. Esto no tiene mucho sentido y parece un error para mí, pero no tiene sentido llamar a getSimpleName() en una clase lambda para comenzar.
  4. Para las clases de matriz, el método getSimpleName() devuelve el nombre simple de la clase del 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 solo [] como sus nombres simples.

Es interesante observar que getCanonicalName() y getSimpleName() pueden generar InternalError cuando el nombre de la clase tiene un formato incorrecto. Esto sucede con algunos lenguajes JVM que no son Java, por ejemplo, Scala.

Considere lo siguiente (Scala 2.11 en 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: String = C

Esto puede ser un problema para entornos de lenguaje mixto o entornos que cargan dinámicamente el código de bytes, por ejemplo, servidores de aplicaciones y otro software de plataforma.


Si no está seguro de algo, intente escribir una prueba primero.

Hice esto:

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

Huellas dactilares:

int int int java.lang.String java.lang.String String java.util.AbstractMap$SimpleEntry java.util.AbstractMap.SimpleEntry SimpleEntry ClassnameTest$1 null

Hay una línea vacía en el último bloque donde getSimpleName devuelve una cadena vacía.

El resultado de esto es:

  • el nombre es el nombre que usaría para cargar dinámicamente la clase con, por ejemplo, una llamada a Class.forName con el ClassLoader predeterminado.
  • el nombre canónico es el nombre que se usaría en una declaración de importación e identifica de forma única la clase. Podría ser útil durante las operaciones de toString o logging.
  • el nombre simple identifica la clase de forma flexible, de nuevo, puede ser útil durante las operaciones de registro o registro, pero no se garantiza que sea único.

También me confundió la amplia gama de diferentes esquemas de nombres, y estaba a punto de preguntar y responder a mi propia pregunta sobre esto cuando encontré esta pregunta aquí. Creo que mis hallazgos encajan bastante bien y complementan lo que ya está aquí. Mi objetivo es buscar documentación sobre los diversos términos y agregar algunos términos más relacionados que puedan surgir en otros lugares.

Considere el siguiente ejemplo:

package a.b; class C { static class D extends C { } D d; D[] ds; }

  • El nombre simple de D es D Esa es la parte que escribiste al declarar la clase. Las clases anónimas no tienen un nombre simple. Class.getSimpleName() devuelve este nombre o la cadena vacía. Es posible que el nombre simple contenga un $ si lo escribe así, ya que $ es una parte válida de un identificador.

  • Según la sección 6.7 de JLS , tanto abCD como abCDDD serían nombres completamente calificados , pero solo abCD sería el nombre canónico de D Así que cada nombre canónico es un nombre completo, pero los convergentes no siempre son verdaderos. Class.getCanonicalName() devolverá el nombre canónico o null .

  • Se documenta que Class.getName() devuelve el nombre binario , como se especifica en la sección 13.1 de JLS . En este caso, devuelve abC$D para D y [La.bC$D; para D[] .

  • Esta respuesta demuestra que es posible que dos clases cargadas por el mismo cargador de clases tengan el mismo nombre canónico pero distintos nombres binarios . Ningún nombre es suficiente para deducir de manera confiable el otro: si tiene el nombre canónico, no sabe qué partes del nombre son paquetes y cuáles contienen clases. Si tiene el nombre binario, no sabe qué $ se introdujeron como separadores y cuáles eran parte de un nombre simple.

  • Las clases anónimas y las clases locales no tienen nombres completos pero aún tienen un nombre binario . Lo mismo se aplica a las clases anidadas dentro de tales clases. Cada clase tiene un nombre binario.

  • Ejecutar javap -v -private en a/b/C.class muestra que el bytecode se refiere al tipo de d como La/b/C$D; y el de la matriz ds como [La/b/C$D; . Estos se denominan descriptores y se especifican en la sección 4.3 de JVMS .

  • El nombre de clase a/b/C$D utilizado en estos dos descriptores es lo que obtiene al reemplazarlo . por / en el nombre binario. La especificación JVM aparentemente llama a esto la forma interna del nombre binario . La sección 4.2.1 de JVMS lo describe, e indica que la diferencia con el nombre binario fue por razones históricas.

  • El nombre de archivo de una clase en uno de los cargadores de clases típicos basados ​​en nombres de archivo es lo que obtiene si interpreta la / en la forma interna del nombre binario como un separador de directorio, y le agrega la extensión de nombre de archivo .class . Se resuelve en relación con la ruta de clase utilizada por el cargador de clases en cuestión.


este es el mejor documento que encontré describiendo 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 string // 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[]


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