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


78

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

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

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



对于读者来说,确实没有理由在邮件中使用这种格式。
无可争议的2011年

Answers:


74

[代表Array,Lsome.type.Here表示类型。这是类似于使用的类型描述符中的字节码内部中看到的Java虚拟机规范的第4.3节-挑选要尽量简短。唯一的区别在于,实际描述符使用/而不是.用于表示包。

例如,对于基元,该值为:[I对于int数组,一个二维数组为:[[I

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

描述符也用于表示字段和方法的类型。

例如:

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

...相当于其参数的方法intdouble以及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


}

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

在此处输入图片说明

参考:有关JVM规范的字段描述


5
Java没有真正的二维数组,但是您可以创建由数组组成的数组。[[I只是表示整数数组。
Jesper

48

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();

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

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

要么

Class.class.isArray();

真好!这就是我想要的
sam,

12

在JNI(通常在内部JVM)中使用它来指示类型。基元用单个字母表示(Z表示布尔值,I表示整数等),[表示数组,L表示类(以a终止;)。

参见此处:JNI类型

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


3
您正在回答另一个问题。实际上,OP明确表示他并不是在问“这意味着什么”。
Nikita Rybak

3
@EboMike问题是“为什么”。这是一个非常有趣的问题,我也想知道答案。虽然“在JVM规范的哪一章中指定了”这个问题没有。
Nikita Rybak

2
我认为问题是“ L”和“ Z”以及其他听起来任意的缩写来自何处。
ide

5
这些不是JNI特定的,而是JVM内部的表示形式。
OscarRyz 2011年

1
@OscarRyz是正确的,这甚至在JNI存在之前就已经成为JVM规范的一部分。JNI正在重用JVM规范中的表示形式,而不是相反。
斯蒂芬·C

9

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

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

  • “ [”表示数组。实际上,数组类型名称是[<typename>where,<typename>是数组基本类型的名称。
  • “ L”实际上是基本类型名称的一部分;例如String为"Ljava.lang.String;"。注意尾随的“;”!

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

为什么?

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

  • 紧凑,
  • 自定界(这对于方法签名的表示很重要,这就是为什么'L'和结尾的';'存在的原因),以及
  • 使用可打印的字符(出于可读性……如果不可读)。

但是不清楚为什么他们决定通过该Class.getName()方法公开数组类型的内部类型名称。我认为他们可以将内部名称映射为更“人性化”的名称。我最大的猜测是,这只是他们直到太晚才解决的问题之一。(没有人是完美的,甚至没有所谓的“智能设计师”。)


6

我认为这是因为C被char占用了,所以上课的下一个字母是L。


2
很好的主意。但是,您是否有任何实际参考证明您是正确的?
GreenGiant

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.