【问题标题】:[L array notation - where does it come from?[L 数组符号 - 它来自哪里?
【发布时间】:2022-09-17 10:09:17
【问题描述】:

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

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

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

【问题讨论】:

  • 查看this post
  • 真的没有理由在人类读者的消息中使用这种格式。

标签: java arrays


【解决方案1】:

[代表数组,Lsome.type.Here;代表数组的类型。这类似于使用的类型描述符在字节码内部见于§4.3 of the Java Virtual Machine Specification——。唯一的区别在于真实的描述符使用 / 而不是 . 来表示包。

例如,对于基元,值为:[I 对于整数数组,二维数组为:[[I(严格来说 Java 没有真正的二维数组,但您可以创建包含以下内容的数组数组)。

由于类可能有任何名称,因此很难确定它是什么类,因此它们以 L 分隔,后跟类名并以 ; 结束

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

例如:

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

...对应一个参数为intdoubleThread,返回类型为Object的方法

编辑

您还可以使用 java 反汇编程序在 .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 行):

参考:Field description on the JVM specification

【讨论】:

  • Java 没有真正的二维数组,但您可以创建由数组组成的数组; [[I 仅表示 array-of-array-of-int。
【解决方案2】:

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

【讨论】:

  • 好的!这就是我要找的
【解决方案3】:

这在 JNI(通常在 JVM 内部)中用于指示类型。基元用单个字母表示(Z 表示布尔值,I 表示整数等),[ 表示数组,L 表示类(以 ; 结尾)。

看这里:JNI Types

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

【讨论】:

  • 你在回答一个不同的问题。事实上,OP 明确表示他不是在问“这是什么意思”。
  • @EboMike 问题是“为什么”。这是一个非常有趣的问题,我也想知道答案。而“在 JVM 规范的哪一章中指定”的问题不是。
  • 我认为问题在于“L”和“Z”以及这些其他听起来随意的缩写词从何而来。
  • 这些不是特定于 JNI 的,而是 JVM 的内部表示。
  • @OscarRyz 是对的,这是 JVM 规范的一部分在 JNI 甚至存在之前. JNI 正在重用 JVM 规范中的表示,而不是相反。
【解决方案4】:

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

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

  • “[”表示数组。事实上,数组类型名称是[&lt;typename&gt;,其中&lt;typename&gt;是数组基类型的名称。
  • 'L'实际上是基本类型名称的一部分;例如字符串是"Ljava.lang.String;"。注意尾随的';'!!

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

为什么?

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

  • 紧凑,
  • 自定界(这对于方法签名的表示很重要,这就是“L”和尾随“;”的原因),以及
  • 使用可打印字符(为了易读性……如果不是可读性)。

但它是不清楚为什么他们决定通过 Class.getName() 方法公开数组类型的内部类型名称。我觉得他们可以已将内部名称映射到更“人性化”的名称。我最好的猜测是,这只是他们直到为时已晚才开始解决的问题之一。 (没有人是完美的......即使是假设的“智能设计师”也是如此。)

【讨论】:

    【解决方案5】:

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

    【讨论】:

    • 很好的主意。但是您有任何实际参考资料可以证明您是正确的吗?
    • 不错..但是 L 本来可以用 Long 的..为什么用 J 来做 Long
    【解决方案6】:

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

    【讨论】:

      猜你喜欢
      • 2019-05-03
      • 1970-01-01
      • 2023-03-30
      • 2014-09-08
      • 1970-01-01
      • 1970-01-01
      • 2011-11-11
      • 2015-04-29
      • 2012-12-09
      相关资源
      最近更新 更多