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 cómo se llaman estos métodos.
Respuestas:
Si no está seguro acerca de algo, intente escribir una prueba primero.
Hice esto:
Huellas dactilares:
Hay una entrada vacía en el último bloque donde
getSimpleName
devuelve una cadena vacía.El resultado final es:
Class.forName
la predeterminadaClassLoader
. Dentro del alcance de un determinadoClassLoader
, todas las clases tienen nombres únicos.toString
las operaciones de registro. Cuando eljavac
compilador tiene una vista completa de un classpath, impone la unicidad de los nombres canónicos dentro de él al confrontar los nombres de clase y paquete totalmente calificados en tiempo de compilación. Sin embargo, las JVM deben aceptar tales conflictos de nombres y, por lo tanto, los nombres canónicos no identifican de forma exclusiva las clases dentro de aClassLoader
. (En retrospectiva, habría sido un mejor nombre para este gettergetJavaName
; pero este método data de una época en que la JVM se usaba únicamente para ejecutar programas Java).toString
las operaciones de registro o, pero no se garantiza que sea único.fuente
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):Este es el resultado completo:
Entonces, aquí están las reglas. Primero, comencemos con los tipos primitivos y
void
:void
, los cuatro métodos simplemente devuelven su nombre.Ahora las reglas para el
getName()
método: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.$$Lambda$
, seguido de un número, seguido de una barra inclinada, seguido de otro número.Z
paraboolean
,B
parabyte
,S
parashort
,C
parachar
,I
paraint
,J
paralong
,F
parafloat
yD
paradouble
. Para las clases y las interfaces que no son matrices, el descriptor de la clase esL
seguido por lo que vienegetName()
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).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:toString()
retornos"interface " + getName()
. Si es un primitivo, vuelve simplementegetName()
. Si es algo más (un tipo de clase, incluso si es bastante raro), regresa"class " + getName()
.El
getCanonicalName()
método:getCanonicalName()
método devuelve exactamente logetName()
que devuelve el método.getCanonicalName()
método devuelvenull
para clases anónimas o locales y para clases de matriz de esos.getCanonicalName()
método devuelve logetName()
que reemplazaría los signos de dólar introducidos por el compilador por puntos.getCanonicalName()
método devuelvenull
si el nombre canónico del tipo de componente esnull
. De lo contrario, devuelve el nombre canónico del tipo de componente seguido de[]
.El
getSimpleName()
método:getSimpleName()
devuelve el nombre de la clase tal como está escrito en el archivo fuente.getSimpleName()
devuelve un vacíoString
.getSimpleName()
just devuelve logetName()
que devolvería sin el nombre del paquete. Esto no tiene mucho sentido y parece un error para mí, pero no tiene sentido llamargetSimpleName()
a una clase lambda para empezar.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.fuente
… replacing the dollar-signs by dots
: Solo se están reemplazando los signos de dólar que se introdujeron como delimitadores. Bien puede tener dólares como parte de un nombre simple, y esos permanecerán en su lugar.Además de las observaciones de Nick Holt, ejecuté algunos casos para
Array
el tipo de datos:Impresiones de fragmentos de código anteriores:
fuente
También me ha confundido la amplia gama de diferentes esquemas de nombres, y estaba a punto de preguntar y responder mi propia pregunta sobre esto cuando encontré esta pregunta aquí. Creo que mis hallazgos encajan lo suficientemente bien y complementan lo que ya está aquí. Mi enfoque es buscar documentación sobre los diversos términos y agregar algunos términos más relacionados que podrían surgir en otros lugares.
Considere el siguiente ejemplo:
El simple nombre de
D
esD
. Esa es solo 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 3.8 de JLS (incluso si se desaconseja un poco).De acuerdo con la sección 6.7 JLS , tanto
a.b.C.D
ya.b.C.D.D.D
sería nombres completos , pero sóloa.b.C.D
sería el nombre canónico deD
. Por lo tanto, cada nombre canónico es un nombre totalmente calificado, pero lo contrario no siempre es cierto.Class.getCanonicalName()
devolverá el nombre canónico onull
.Class.getName()
está documentado para devolver el nombre binario , tal como se especifica en la sección 13.1 de JLS . En este caso, devuelvea.b.C$D
porD
y[La.b.C$D;
paraD[]
.Esta respuesta demuestra que es posible que dos clases cargadas por el mismo cargador de clases tengan el mismo nombre canónico pero nombres binarios distintos . Ninguno de los dos nombres 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 cuáles
$
se introdujeron como separadores y cuáles fueron parte de un nombre simple. (El archivo de clase almacena el nombre binario de la clase en sí y su clase adjunta , lo que permite que el tiempo de ejecución haga esta distinción ).Las clases anónimas y las clases locales no tienen nombres completos, pero aún tienen un nombre binario . Lo mismo vale para las clases anidadas dentro de tales clases. Cada clase tiene un nombre binario.
Correr
javap -v -private
ena/b/C.class
muestra que el código de bytes se refiere al tipo ded
comoLa/b/C$D;
y el de la matrizds
como[La/b/C$D;
. Estos se denominan descriptores y se especifican en la sección 4.3 de JVMS .El nombre de la clase
a/b/C$D
utilizada en estos dos descriptores es lo que se obtiene mediante la sustitución.
por/
el nombre del archivo 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 y establece que la diferencia con el nombre binario se debe a razones históricas.El nombre de archivo de una clase en uno de los cargadores de clases típicos basados en nombre de archivo es lo que obtienes si interpretas el
/
en forma interna del nombre binario como un separador de directorio y le agregas 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.fuente
este es el mejor documento que encontré que describe 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/
fuente
Es interesante notar eso
getCanonicalName()
ygetSimpleName()
puede aparecerInternalError
cuando el nombre de la clase está mal formado. Esto sucede para algunos lenguajes JVM que no son Java, por ejemplo, Scala.Considere lo siguiente (Scala 2.11 en Java 8):
Esto puede ser un problema para entornos de idiomas mixtos o entornos que cargan dinámicamente bytecode, por ejemplo, servidores de aplicaciones y otro software de plataforma.
fuente
getName () : devuelve el nombre de la entidad (clase, interfaz, clase de matriz, tipo primitivo o vacío) representada por este objeto de clase, como una cadena.
getCanonicalName () : devuelve el nombre canónico de la clase subyacente tal como se define en la Especificación del lenguaje Java.
getSimpleName () : devuelve el nombre simple de la clase subyacente, es decir, el nombre que se le ha dado en el código fuente.
Una diferencia es que si usa una clase anónima, puede obtener un valor nulo al intentar obtener el nombre de la clase usando
getCanonicalName()
Otro hecho es que el
getName()
método se comporta de manera diferente que elgetCanonicalName()
método para las clases internas .getName()
usa un dólar como separador entre el nombre canónico de la clase que lo encierra y el nombre simple de la clase interna.Para saber más sobre cómo recuperar un nombre de clase en Java .
fuente
fuente
Class<StringBuffer> clazz = StringBuffer.class