[L数组符号 - 它来自哪里?

Mic*_*rry 76 java arrays

我经常看到使用[L类型来表示数组的消息,例如:

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

(上面是我刚刚拔出的任意例子.)我知道这表示一个数组,但语法来自何处?为什么开始[但没有关闭方括号?为什么L?这纯粹是武断的还是还有其他一些历史/技术原因?

Osc*_*Ryz 70

[代表数组,Lsome.type.Here意思是类型.这类似于Java虚拟机规范§4.3中所见的字节码内部使用的类型描述符- 选择尽可能简短.唯一的区别在于真正的描述符使用而不是表示包./.

例如,对于基元,值为:[I对于int数组,二维数组将为:[[I.

由于类可能有任何名称,因此更难识别它是什么类,因此L,类名以a结尾;

描述符还用于表示字段和方法的类型.

例如:

(IDLjava/lang/Thread;)Ljava/lang/Object;
Run Code Online (Sandbox Code Playgroud)

...相当于其参数的方法int,double以及Thread和返回类型为Object

编辑

您还可以使用java dissambler在.class文件中看到此内容

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


}
Run Code Online (Sandbox Code Playgroud)

在原始类文件中(见第5行):

在此输入图像描述

参考:JVM规范的字段描述

  • Java没有真正的二维数组,但你可以创建由数组组成的数组; `[[我只是指array-of-array-of-int. (4认同)

小智 46

JVM数组描述符.

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

要获取主数据类型,您需要:

[Object].getClass().getComponentType();
Run Code Online (Sandbox Code Playgroud)

如果"对象"不是数组,它将返回null.要确定它是否是一个数组,只需调用:

[Any Object].getClass().isArray()
Run Code Online (Sandbox Code Playgroud)

要么

Class.class.isArray();
Run Code Online (Sandbox Code Playgroud)


Ebo*_*ike 11

这在JNI(以及一般内部的JVM)中用于指示类型.基元用单个字母表示(Z表示布尔值,I表示int [表示等),表示数组,L表示类(由a终止;).

见这里:JNI类型

编辑:详细说明为什么没有终止]- 这段代码是允许JNI/JVM快速识别方法及其签名.它旨在尽可能紧凑,以便快速解析(=尽可能少的字符),因此[用于一个非常简单的数组(使用什么更好的符号?).Ifor int同样显而易见.

  • 这些不是JNI特定的,而是JVM内部表示. (5认同)
  • 你正在回答一个不同的问题.事实上,OP明确表示他不会问"这是什么意思". (3认同)
  • @EboMike问题是'为什么'.这是一个非常有趣的问题,我也想知道答案.虽然"JVM spec中指定的哪一章"的问题不是. (3认同)
  • 我认为问题是“L”和“Z”以及其他听起来随意的缩写来自哪里。 (2认同)
  • @OscarRyz 是对的,这是 JVM 规范的一部分*在 JNI 存在之前*。JNI 正在重用 JVM 规范中的表示,而不是相反。 (2认同)

Ste*_*n C 9

[L数组符号 - 它来自哪里?

来自JVM规范.这是在classFile格式和其他位置指定的类型名称的表示形式.

  • '['表示一个数组.实际上,阵列类型名称是[<typename>其中<typename>是基本类型的数组的名称.
  • 'L'实际上是基本类型名称的一部分; 例如,String是"Ljava.lang.String;".注意尾随';'!!

是的,该符号也记录在其他地方.

为什么?

毫无疑问,选择内部类型名称表示是因为它是:

  • 紧凑,
  • 自我划分(这对于方法签名的表示很重要,这就是为什么'L'和尾随';'在那里),以及
  • 使用可打印字符(易读性......如果不可读).

但目前还不清楚为什么他们决定通过该Class.getName()方法公开数组类型的内部类型名称.我认为他们可以将内部名称映射到更"人性化"的东西.我最好的猜测是,这只是他们没有解决的事情之一,直到为时已晚.(没有人是完美的......甚至不是假设的"智能设计师".)


Ene*_*cio 5

我想这是因为C是char,所以下一个字母是L.

  • 好点子。但是你有任何实际的参考资料来证明你是正确的吗? (2认同)