[L数组符号 – 它从哪里来?

我经常看到使用[L然后是一个types来表示一个数组的消息,例如:

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

(以上是我刚刚拿出的一个任意例子。)我知道这表示一个数组,但语法从哪里来? 为什么开始[但没有closures方括号? 为什么L? 它是纯粹的武断还是有其他一些背后的历史/技术原因?

[代表arrays, Lsome.type.Here表示types。 这与在Java虚拟机规范的§4.3中看到的字节码内部使用的types描述符类似 – select的越 简单越好 。 唯一的区别在于真正的描述符使用/而不是. 用于表示包。

例如,对于原语,值是: [I对于int数组,一个二维数组将是: [[I

由于类可能有任何名字,所以很难确定它是什么类,因此L ,类名以a结尾;

描述符也被用来表示字段和方法的types。

例如:

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

…对应于参数为intdoubleThread且返回types为Object

编辑

你也可以使用java disambler在.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 } 

而在原始类文件(看第5行):

在这里输入图像描述

参考: JVM规范的字段描述

JVM数组描述符。

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

要获得主要的数据types,您需要:

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

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

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

要么

 Class.class.isArray(); 

这在JNI(通常是内部的JVM)中用来表示一个types。 图元用单个字母表示(Z表示布尔型,I表示int型), [表示一个数组,L表示一个类(以a结尾)。

看到这里: JNItypes

编辑:阐述为什么没有终止] – 这个代码是为了让JNI / JVM快速识别一个方法及其签名。 它的目的是使得parsing速度尽可能的紧凑(尽可能less的字符),所以[用于一个非常简单的数组(比较好的符号)。 I为int也同样明显。

[L数组符号 – 它从哪里来?

从JVM规范。 这是在classFile格式和其他地方指定的types名称的表示forms。

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

是的,这个符号也被logging在其他地方。

为什么?

毫无疑问,select内部types名称表示是因为它是:

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

但是目前还不清楚为什么他们决定通过Class.getName()方法公开数组types的内部types名称。 我认为他们可以把内部的名字映射到更“人性化”的东西上。 我最好的猜测是,这只是其中一件事情,他们没有得到解决,直到为时已晚。 (没有人是完美的……甚至不是假设的“聪明的devise师”。)

另一个来源是Class.getName()的文档。 当然,所有这些规格都是一致的,因为它们是相互适应的。

我想这是因为C被字符占据,所以下一个字母是L