[Notación de matriz L - ¿de dónde viene?

79

A menudo he visto mensajes que usan [Lun tipo para denotar una matriz, por ejemplo:

[Ljava.lang.Object; cannot be cast to [Ljava.lang.String;

(Lo anterior es un ejemplo arbitrario que acabo de extraer). Sé que esto significa una matriz, pero ¿de dónde proviene la sintaxis? ¿Por qué el principio [pero no el corchete de cierre? ¿Y por qué la L? ¿Es puramente arbitrario o hay alguna otra razón histórica / técnica detrás de esto?

Michael Berry
fuente
3
echa un vistazo a esta publicación
Bala R
Realmente no hay ninguna razón para utilizar este formato en mensajes para lectores humanos.
irrefutable

Respuestas:

74

[significa Array, Lsome.type.Heresignifica el tipo. Eso es similar a los descriptores de tipo utilizados internamente en el código de bytes que se ve en §4.3 de la Especificación de la máquina virtual de Java , elegido para ser lo más breve posible . La única diferencia es que los descriptores reales utilizan en /lugar de. para denotar paquetes.

Por ejemplo, para las primitivas el valor es: [Ipara matriz de int, una matriz de dos dimensiones sería el siguiente: [[I.

Dado que las clases pueden tener cualquier nombre, sería más difícil identificar qué clase es, por lo tanto L, el nombre de la clase termina con un;

Los descriptores también se utilizan para representar los tipos de campos y métodos.

Por ejemplo:

(IDLjava/lang/Thread;)Ljava/lang/Object;

... corresponde a un método cuyos parámetros son int, doubley Thready el tipo de retorno esObject

editar

También puede ver esto en archivos .class usando el dissambler java

C:>more > S.java
class S {
  Object  hello(int i, double d, long j, Thread t ) {
   return new Object();
  }
}
^C
C:>javac S.java

C:>javap -verbose S
class S extends java.lang.Object
  SourceFile: "S.java"
  minor version: 0
  major version: 50
  Constant pool:
const #1 = Method       #2.#12; //  java/lang/Object."<init>":()V
const #2 = class        #13;    //  java/lang/Object
const #3 = class        #14;    //  S
const #4 = Asciz        <init>;
const #5 = Asciz        ()V;
const #6 = Asciz        Code;
const #7 = Asciz        LineNumberTable;
const #8 = Asciz        hello;
const #9 = Asciz        (IDJLjava/lang/Thread;)Ljava/lang/Object;;
const #10 = Asciz       SourceFile;
const #11 = Asciz       S.java;
const #12 = NameAndType #4:#5;//  "<init>":()V
const #13 = Asciz       java/lang/Object;
const #14 = Asciz       S;

{
S();
  Code:
   Stack=1, Locals=1, Args_size=1
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return
  LineNumberTable:
   line 1: 0


java.lang.Object hello(int, double, long, java.lang.Thread);
  Code:
   Stack=2, Locals=7, Args_size=5
   0:   new     #2; //class java/lang/Object
   3:   dup
   4:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   7:   areturn
  LineNumberTable:
   line 3: 0


}

Y en el archivo de clase sin formato (mire la línea 5):

ingrese la descripción de la imagen aquí

Referencia: descripción de campo en la especificación de JVM

OscarRyz
fuente
5
Java no tiene matrices bidimensionales reales, pero puede crear matrices que consistan en matrices; [[Isolo significa matriz-de-matriz-de-int.
Jesper
49

Descriptores de matriz de JVM.

[Z = boolean
[B = byte
[S = short
[I = int
[J = long
[F = float
[D = double
[C = char
[L = any non-primitives(Object)

Para obtener el tipo de datos principal, necesita:

[Object].getClass().getComponentType();

Devolverá nulo si el "objeto" no es una matriz. para determinar si es una matriz, simplemente llame a:

[Any Object].getClass().isArray()

o

Class.class.isArray();
Dino Rico Bendanillo
fuente
¡Agradable! Esto es lo que estaba buscando
sam
12

Esto se usa en la JNI (y la JVM internamente en general) para indicar un tipo. Las primitivas se indican con una sola letra (Z para booleano, I para int, etc.), [indica una matriz y L se usa para una clase (terminada por una; ).

Vea aquí: Tipos de JNI

EDITAR: Para explicar por qué no hay terminación ], este código es para permitir que JNI / JVM identifique rápidamente un método y su firma. Está destinado a ser lo más compacto posible para agilizar el análisis (= la menor cantidad de caracteres posible), por lo que [se usa para una matriz que es bastante sencilla (¿qué mejor símbolo para usar?). Iporque int es igualmente obvio.

EboMike
fuente
3
Estás respondiendo una pregunta diferente. De hecho, OP ha declarado explícitamente que no está preguntando "qué significa".
Nikita Rybak
3
@EboMike La pregunta es 'por qué'. Y esa es una pregunta muy interesante, también me gustaría saber la respuesta. Mientras que la pregunta "en qué capítulo de la especificación de JVM se especifica" no lo es.
Nikita Rybak
2
Creo que la pregunta es de dónde vienen "L" y "Z" y estas otras abreviaturas que suenan arbitrarias.
ide
5
Estos no son específicos de JNI sino representación interna de JVM.
OscarRyz
1
@OscarRyz tiene razón, esto era parte de la especificación JVM antes de que existiera JNI . JNI está reutilizando la representación en la especificación de JVM, no al revés.
Stephen C
9

[Notación de matriz L - ¿de dónde viene?

De la especificación de JVM. Esta es la representación de los nombres de tipo que se especifica en el formato classFile y en otros lugares.

  • El '[' denota una matriz. De hecho, el nombre del tipo de matriz es [<typename>donde <typename>está el nombre del tipo base de la matriz.
  • 'L' es en realidad parte del nombre del tipo base; por ejemplo, String es "Ljava.lang.String;". ¡¡Tenga en cuenta el ';' !!

Y sí, la notación también está documentada en otros lugares.

¿Por qué?

No hay duda de que se eligió esa representación de nombre de tipo interno porque es:

  • compacto,
  • auto delimitador (esto es importante para las representaciones de firmas de métodos, y es por eso que la 'L' y el final ';' están ahí), y
  • utiliza caracteres imprimibles (para legibilidad ... si no legibilidad).

Pero no está claro por qué decidieron exponer los nombres de tipos internos de los tipos de matriz a través del Class.getName()método. Creo que podrían haber asignado los nombres internos a algo más "amigable para los humanos". Mi mejor suposición es que fue solo una de esas cosas que no pudieron arreglar hasta que fue demasiado tarde. (Nadie es perfecto ... ni siquiera el hipotético "diseñador inteligente").

Stephen C
fuente
6

Creo que es porque C fue tomado por char, así que la siguiente letra en clase es L.

Enerccio
fuente
2
Gran idea. Pero, ¿tiene alguna referencia real que demuestre que está en lo cierto?
GreenGiant
3

Otra fuente para esto sería la documentación de Class.getName () . Por supuesto, todas estas especificaciones son congruentes, ya que están hechas para encajar entre sí.

Paŭlo Ebermann
fuente