[L notation de tableau – d’où vient-il?

J’ai souvent vu des messages qui utilisent [L alors un type pour désigner un tableau, par exemple:

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

(Ce qui précède est un exemple arbitraire que je viens de sortir.) Je sais que cela signifie un tableau, mais d’où vient la syntaxe? Pourquoi le début [ mais pas de crochets fermants? Et pourquoi le L? Est-ce purement arbitraire ou y a-t-il une autre raison historique / technique derrière cela?

[ signifie Array, le Lsome.type.Here le type. Cela est similaire aux descripteurs de type utilisés en interne dans le bytecode du § 4.3 de la spécification de la machine virtuelle Java – choisis pour être aussi brefs que possible . La seule différence réside dans le fait que les descripteurs réels utilisent / plutôt que . pour signaler des paquets.

Par exemple, pour les primitives, la valeur est la suivante: [I pour tableau de int, un tableau à deux dimensions serait: [[I

Comme les classes peuvent avoir un nom quelconque, il serait plus difficile d’identifier la classe, d’où le L , le nom de la classe se termine par un ;

Les descripteurs sont également utilisés pour représenter les types de champs et de méthodes.

Par exemple:

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

… correspond à une méthode dont les parameters sont int , double et Thread et le type de retour est Object

modifier

Vous pouvez également voir cela dans les fichiers .class en utilisant le 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."":()V const #2 = class #13; // java/lang/Object const #3 = class #14; // S const #4 = Asciz ; 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;// "":()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."":()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."":()V 7: areturn LineNumberTable: line 3: 0 } 

Et dans le fichier de classe brut (regardez la ligne 5):

entrer la description de l'image ici

Référence: Description du champ sur la spécification de la JVM

Descripteurs de tableaux JVM.

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

Pour obtenir le type de données principal, vous avez besoin de:

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

Il retournera null si “l’object” n’est pas un tableau. pour déterminer s’il s’agit d’un tableau, appelez simplement:

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

ou

 Class.class.isArray(); 

Ceci est utilisé dans le JNI (et la JVM en interne en général) pour indiquer un type. Les primitives sont désignées par une seule lettre (Z pour booléen, I pour int, etc.), [ indique un tableau et L est utilisé pour une classe (terminée par un ; ).

Voir ici: Types JNI

EDIT: pour expliquer pourquoi il n’y a pas de terminaison ] – ce code doit permettre à JNI / JVM d’identifier rapidement une méthode et sa signature. Il est conçu pour être aussi compact que possible afin de permettre une parsing rapide (= aussi peu de caractères que possible), donc [ est utilisé pour un tableau assez simple (quel meilleur symbole à utiliser?). I pour int est tout aussi évident.

[L notation de tableau – d’où vient-il?

De la spécification JVM. C’est la représentation des noms de type spécifiés dans le format classFile et à d’autres endroits.

  • Le ‘[‘ désigne un tableau. En fait, le nom du type de tableau est [ est le nom du type de base du tableau.
  • ‘L’ fait en réalité partie du nom du type de base; Par exemple, la chaîne est "Ljava.lang.Ssortingng;" . Notez le suivi ‘;’ !!

Et oui, la notation est également documentée ailleurs.

Pourquoi?

Il ne fait aucun doute que cette représentation de nom de type interne a été choisie car elle est:

  • compact,
  • auto-délimitation (ceci est important pour les représentations de signatures de méthodes, et c’est pourquoi le «L» et le «;» sont présents), et
  • utilise des caractères imprimables (lisibilité, sinon lisibilité).

Mais on ne sait pas pourquoi ils ont décidé d’exposer les noms de types internes de types de tableaux via la méthode Class.getName() . Je pense qu’ils auraient pu faire correspondre les noms internes à quelque chose de plus “humain”. Ma meilleure supposition est que ce n’était qu’une de ces choses qu’ils n’avaient pas réussi à régler avant qu’il ne soit trop tard. (Personne n’est parfait … pas même l’hypothétique “designer intelligent”.)

Je pense que c’est parce que C a été pris par char, donc la prochaine lettre en classe est L.

Une autre source pour cela serait la documentation de Class.getName () . Bien entendu, toutes ces spécifications sont cohérentes, car elles sont adaptées les unes aux autres.