[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;
…对应于参数为int
, double
和Thread
且返回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