[Позначення масиву L - звідки воно береться?


79

Я часто бачив повідомлення, які використовують [Lтоді тип для позначення масиву, наприклад:

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

(Наведене вище є довільним прикладом, який я щойно витягнув.) Я знаю, що це означає масив, але звідки береться синтаксис? Чому початок, [але відсутність закриває квадратну дужку? А чому L? Це суто довільне чи за цим ховається якась інша історична / технічна причина?


3
перегляньте цю публікацію
Bala R

Насправді немає причин використовувати цей формат у повідомленнях для читачів.
беззаперечний

Відповіді:


74

[означає Array, Lsome.type.Hereозначає тип. Це схоже на дескриптори типів, що використовуються всередині байт-коду, як це видно в §4.3 Специфікації віртуальної машини Java - вибрані максимально короткими . Різниця лише в тому, що справжні дескриптори використовують, /а не .для позначення пакетів.

Наприклад, для примітивів значення: [Iдля масиву Міжнар, двовимірний масив буде: [[I.

Оскільки класи можуть мати будь-яку назву, було б важче визначити, що це за клас, отже L, назва класу закінчується на;

Дескриптори також використовуються для представлення типів полів і методів.

Наприклад:

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

... відповідає методі , чиї параметри int, doubleі Threadта типу значення, що повертаєтьсяObject

редагувати

Ви також можете побачити це у файлах .class за допомогою програми розширювача 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


}

І у файлі класу raw (див. Рядок 5):

введіть тут опис зображення

Довідково: Опис поля в специфікації JVM


5
Java не має реальних двовимірних масивів, але ви можете створювати масиви, що складаються з масивів; [[Iпросто означає array-of-array-of-int.
Jesper

49

Дескриптори масиву JVM.

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

Щоб отримати основний тип даних, вам потрібно:

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

Він поверне нуль, якщо "об'єкт" не є масивом. щоб визначити, чи це масив, просто зателефонуйте:

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

або

Class.class.isArray();

Приємно! Це те, що я шукав
сам

12

Це використовується в JNI (і JVM внутрішньо загалом) для позначення типу. Примітиви позначаються однією літерою (Z для булевої, I для int тощо), [позначає масив, а L використовується для класу (закінчується a ;).

Дивіться тут: Типи JNI

РЕДАКТУВАТИ: щоб детальніше пояснити, чому немає припинення ]- цей код повинен дозволити JNI / JVM швидко ідентифікувати метод та його підпис. Він призначений максимально компактним для швидкого синтаксичного аналізу (= якомога менше символів), тому [використовується для масиву, який є досить простим (який кращий символ використовувати?). Iадже int однаково очевидно.


3
Ви відповідаєте на інше запитання. Насправді OP чітко заявив, що не запитує, "що це означає".
Микита Рибак

3
@EboMike Питання в тому, чому. І це дуже цікаве питання, я б теж хотів знати відповідь. Хоча питання "в якому розділі специфікації JVM це вказано" немає.
Микита Рибак

2
Думаю, питання полягає в тому, звідки походять "L" та "Z" та ці інші довільно звучачі скорочення.
ide

5
Це не JNI, а внутрішнє представництво JVM.
OscarRyz

1
@OscarRyz має рацію, це було частиною специфікації JVM ще до існування JNI . JNI повторно використовує представлення в специфікації JVM, а не навпаки.
Stephen C

9

[Позначення масиву L - звідки воно береться?

З специфікації JVM. Це подання імен типів, яке вказано у форматі classFile та інших місцях.

  • '[' Позначає масив. Насправді, ім'я типу масиву - це [<typename>де <typename>є ім'я базового типу масиву.
  • 'L' насправді є частиною назви базового типу; наприклад String є "Ljava.lang.String;". Зверніть увагу на кінцевий ';' !!

І так, позначення зафіксовано і в інших місцях.

Чому?

Немає сумнівів, що саме те внутрішнє подання імені типу було обрано, оскільки це:

  • компактний,
  • саморозмежування (це важливо для подання підписів методів, і тому там є "L" і кінцевий ";"), і
  • використовує друковані символи (для читабельності ... якщо не для читабельності).

Але незрозуміло, чому вони вирішили викрити внутрішні імена типів типів масивів за допомогою Class.getName()методу. Думаю, вони могли перетворити внутрішні імена на щось більш «дружнє до людини». Я найкраще здогадуюсь, що це була лише одна з тих речей, яку вони не змогли виправити, поки не було пізно. (Ніхто не ідеальний ... навіть гіпотетичний "розумний дизайнер".)


6

Я думаю, це тому, що С взяв char, тож наступна буква в класі - L.


2
Чудова ідея. Але чи є у вас фактичні посилання, щоб показати, що ви правильні?
GreenGiant

3

Іншим джерелом цього може бути документація Class.getName () . Звичайно, всі ці технічні характеристики є конгруентними, оскільки вони зроблені так, щоб відповідати один одному.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.