[L-Array-Notation - woher kommt sie?

78

Ich habe oft Nachrichten gesehen, die [Ldann einen Typ verwenden, um ein Array zu bezeichnen, zum Beispiel:

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

(Das obige ist ein willkürliches Beispiel, das ich gerade herausgezogen habe.) Ich weiß, dass dies ein Array bedeutet, aber woher kommt die Syntax? Warum der Anfang, [aber keine schließende eckige Klammer? Und warum das L? Ist es rein willkürlich oder gibt es einen anderen historischen / technischen Grund dafür?

Michael Berry
quelle
3
Schauen Sie sich diesen Beitrag an
Bala R
Es gibt wirklich keinen Grund, dieses Format in Nachrichten für menschliche Leser zu verwenden.
unwiderlegbar

Antworten:

74

[steht für Array, Lsome.type.Herebedeutet den Typ. Dies ähnelt den Typdeskriptoren, die intern im Bytecode in §4.3 der Java Virtual Machine-Spezifikation verwendet werden - so kurz wie möglich . Der einzige Unterschied besteht darin, dass die realen Deskriptoren /eher .Pakete als Bezeichnungen verwenden.

Für Grundelemente lautet der Wert beispielsweise: [IFür ein Array von int wäre ein zweidimensionales Array : [[I.

Da Klassen einen beliebigen Namen haben können, ist es schwieriger zu identifizieren, um welche Klasse es sich handelt. Daher Lendet der Klassenname mit einem;

Deskriptoren werden auch verwendet, um die Arten von Feldern und Methoden darzustellen.

Zum Beispiel:

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

... entspricht ein Verfahren , deren Parameter sind int, doubleund Threadund der Rücklauftyp istObject

bearbeiten

Sie können dies auch in .class-Dateien sehen, die den Java-Dissambler verwenden

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


}

Und in der Rohklassendatei (siehe Zeile 5):

Geben Sie hier die Bildbeschreibung ein

Referenz: Feldbeschreibung in der JVM-Spezifikation

OscarRyz
quelle
5
Java hat keine echten zweidimensionalen Arrays, aber Sie können Arrays erstellen, die aus Arrays bestehen. [[Ibedeutet nur Array-of-Array-of-Int.
Jesper
48

JVM-Array-Deskriptoren.

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

Um den Hauptdatentyp zu erhalten, benötigen Sie:

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

Es wird null zurückgegeben, wenn das "Objekt" kein Array ist. Um festzustellen, ob es sich um ein Array handelt, rufen Sie einfach Folgendes auf:

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

oder

Class.class.isArray();
Dino Rico Bendanillo
quelle
Nett! Dies ist, was ich gesucht habe
Sam
12

Dies wird in der JNI (und der JVM intern im Allgemeinen) verwendet, um einen Typ anzugeben. Grundelemente werden mit einem einzelnen Buchstaben bezeichnet (Z für Boolescher Wert, I für Int usw.), [geben ein Array an und L wird für eine Klasse verwendet (mit a abgeschlossen ;).

Siehe hier: JNI-Typen

BEARBEITEN: Um herauszufinden, warum es keine Beendigung gibt ]- dieser Code soll es der JNI / JVM ermöglichen, eine Methode und ihre Signatur schnell zu identifizieren. Es soll so kompakt wie möglich sein, um das Parsen schnell zu machen (= so wenig Zeichen wie möglich). Es wird daher [für ein Array verwendet, das ziemlich einfach ist (welches bessere Symbol ist zu verwenden?). Ifür int ist ebenso offensichtlich.

EboMike
quelle
3
Sie beantworten eine andere Frage. Tatsächlich hat OP ausdrücklich erklärt, dass er nicht fragt, "was es bedeutet".
Nikita Rybak
3
@EboMike Die Frage ist 'warum'. Und das ist eine sehr interessante Frage, ich würde auch gerne die Antwort wissen. Die Frage "In welchem ​​Kapitel der JVM-Spezifikation ist sie angegeben?" Ist dies nicht.
Nikita Rybak
2
Ich denke, die Frage ist, woher "L" und "Z" und diese anderen willkürlich klingenden Abkürzungen kommen.
Ide
5
Dies sind keine JNI-spezifischen, sondern JVM-interne Darstellungen.
OscarRyz
1
@OscarRyz ist richtig, dies war Teil der JVM-Spezifikation, bevor JNI überhaupt existierte . JNI verwendet die Darstellung in der JVM-Spezifikation wieder, nicht umgekehrt.
Stephen C
9

[L-Array-Notation - woher kommt sie?

Aus der JVM-Spezifikation. Dies ist die Darstellung von Typnamen, die im classFile-Format und an anderen Stellen angegeben ist.

  • Das '[' bezeichnet ein Array. In der Tat ist der Array Typname , [<typename>wo <typename>der Name des Basistypen des Arrays ist.
  • 'L' ist tatsächlich Teil des Basistypnamens; zB String ist "Ljava.lang.String;". Beachten Sie das nachfolgende ';' !!

Und ja, die Notation ist auch an anderen Stellen dokumentiert.

Warum?

Es besteht kein Zweifel, dass diese interne Typnamenrepräsentation ausgewählt wurde, weil es ist:

  • kompakt,
  • selbstabgrenzend (dies ist wichtig für die Darstellung von Methodensignaturen, und deshalb sind das 'L' und das nachgestellte ';' da) und
  • verwendet druckbare Zeichen (zur besseren Lesbarkeit ... wenn nicht lesbar).

Es ist jedoch unklar, warum sie beschlossen haben, die internen Typnamen von Array-Typen über die Class.getName()Methode verfügbar zu machen. Ich denke , sie könnten die internen Namen zu etwas mehr „human friendly“ zugeordnet haben. Meine beste Vermutung ist, dass es nur eines dieser Dinge war, die sie erst reparieren konnten, als es zu spät war. (Niemand ist perfekt ... nicht einmal der hypothetische "intelligente Designer".)

Stephen C.
quelle
6

Ich denke, das liegt daran, dass C von char genommen wurde, also ist der nächste Buchstabe in der Klasse L.

Enerccio
quelle
2
Großartige Idee. Aber haben Sie tatsächliche Referenzen, die zeigen, dass Sie korrekt sind?
GreenGiant
3

Eine weitere Quelle hierfür wäre die Dokumentation von Class.getName () . Natürlich sind alle diese Spezifikationen kongruent, da sie aufeinander abgestimmt sind.

Paŭlo Ebermann
quelle