我经常看到消息,[L
然后使用类型来表示数组,例如:
[Ljava.lang.Object; cannot be cast to [Ljava.lang.String;
(以上是我刚刚拔出的一个任意示例。)我知道这表示一个数组,但是语法从何而来?为什么要开始[
却没有结束方括号?为什么是L?它是纯粹武断的还是背后有其他历史/技术原因?
我经常看到消息,[L
然后使用类型来表示数组,例如:
[Ljava.lang.Object; cannot be cast to [Ljava.lang.String;
(以上是我刚刚拔出的一个任意示例。)我知道这表示一个数组,但是语法从何而来?为什么要开始[
却没有结束方括号?为什么是L?它是纯粹武断的还是背后有其他历史/技术原因?
Answers:
[
代表Array,Lsome.type.Here
表示类型。这是类似于使用的类型描述符中的字节码内部中看到的Java虚拟机规范的第4.3节-挑选要尽量简短。唯一的区别在于,实际描述符使用/
而不是.
用于表示包。
例如,对于基元,该值为:[I
对于int数组,一个二维数组为:[[I
。
由于类可以有任何名称,因此很难确定它是什么类,因此L
,类名以a结尾;
描述符也用于表示字段和方法的类型。
例如:
(IDLjava/lang/Thread;)Ljava/lang/Object;
...相当于其参数的方法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
}
在原始类文件中(请看第5行):
参考:有关JVM规范的字段描述
[[I
只是表示整数数组。
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();
在JNI(通常在内部JVM)中使用它来指示类型。基元用单个字母表示(Z表示布尔值,I表示整数等),[
表示数组,L表示类(以a终止;
)。
参见此处:JNI类型
编辑:详细说明为什么没有终止]
-此代码是允许JNI / JVM快速识别方法及其签名。它旨在尽可能紧凑以使解析速度更快(=尽可能少的字符),因此[
用于非常简单的数组(使用哪种更好的符号?)。I
对于int同样明显。
[L数组符号-它来自哪里?
来自JVM规范。这是在classFile格式和其他位置指定的类型名称的表示。
[<typename>
where,<typename>
是数组基本类型的名称。"Ljava.lang.String;"
。注意尾随的“;”!是的,该符号也记录在其他地方。
为什么?
毫无疑问,选择内部类型名称表示是因为:
但是不清楚为什么他们决定通过该Class.getName()
方法公开数组类型的内部类型名称。我认为他们可以将内部名称映射为更“人性化”的名称。我最大的猜测是,这只是他们直到太晚才解决的问题之一。(没有人是完美的,甚至没有所谓的“智能设计师”。)
另一个来源是Class.getName()的文档。当然,所有这些规范都是一致的,因为它们相互适合。