JVM是怎么实现数组的class的?
How did JVM implement array's class?
我可以覆盖 array
的任何方法吗?
例如toString()
或其他方法。
import java.lang.reflect.Method;
public class ArraysClassTest {
static int[] array = { 1, 2, 3, 1 };
public static void main(String[] args) {
Class<? extends int[]> class1 = array.getClass();
try {
Method method = class1.getMethod("toString");
} catch (NoSuchMethodException | SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
在Java中,所有数组(包括基本类型的数组)都以java.lang.Object
作为基数class。 (一方面,这是零长度数组的建模方式)。
尽管可以覆盖该基 class 中的任何方法,但 Java 本身指定了数组的形式。你不能干涉它:特别是你不能 extend
一个数组。
回答你的直接问题:不,你不能。
数组是一种 "compiler" 结构——编译器知道 String[] 的含义;并从中创建相应的字节码。只能创建数组对象,不能"new array classes"。或者除此之外,JVM 知道如何处理 "array using" 字节码指令。
换句话说:定义数组对象行为的源代码完全不受您的控制。数组只是做数组做的事;你没办法干涉它。
然后回答你隐含的问题为什么会这样:
有时候理解的东西并不多;但只需接受。问题是 Java 语言是在将近 20 多年前创建的;在某些时候,一些人做出了一些设计选择。他们中的许多人都很优秀;如果我们现在重做一些事情,其中一些可能已经得到处理。
例如,您会发现 Scala 有不同的处理数组的方式。但是对于java,事情就是这样;尤其是对于 "so core" 语言作为数组的东西,现在改变任何东西都没有意义。
您可以创建一个代理并使用它来代替原始对象
final int[] array = { 1, 2, 3, 1 };
Object proxy = Proxy.newProxyInstance(array.getClass().getClassLoader(), array.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
StringBuilder b=new StringBuilder("the array is");
for(int i:array)
b.append(" ").append(i);
return b.toString();
}
});
System.out.println(proxy.toString());
上面的输出是“数组是 1 2 3 1”。
您不能更改数组的任何功能。 JLS §10.7 Array Members 指定数组的每个成员:
The members of an array type are all of the following:
The public
final
field length
, which contains the number of components of the array. length
may be positive or zero.
The public
method clone
, which overrides the method of the same name in class Object
and throws no checked exceptions. The return type of the clone
method of an array type T[]
is T[]
.
A clone of a multidimensional array is shallow, which is to say that it creates only a single new array. Subarrays are shared.
All the members inherited from class Object
; the only method of Object
that is not inherited is its clone
method.
规范不允许以任何方式自定义此实现。例如,数组的 toString()
方法始终是从 Object
.
继承的基本方法
为了创建数组对象,编译器将三个指令之一发送到已编译的 Java bytecode: newarray
for primitives, anewarray
for reference types, or multinewarray
for all multidimensional arrays. In implementing those instructions, the virtual machine creates each array class as needed at runtime (JVMS §5.3.3 Creating Array Classes)。 VM 还为编译器定义了专用的字节码指令,用于获取和设置数组元素以及获取数组的长度。
如何 数组在 VM 中实现没有任何规定。它纯粹是一个实现细节,甚至 Java 编译器也不知道,也不关心。实际涉及的代码取决于您 运行 您的程序所在的虚拟机的风格、该 VM 的版本、OS 和 CPU 它 运行 所在的,以及VM 配置的任何相关运行时选项(例如,是否处于解释模式)。
快速浏览 OpenJDK 8 源代码会发现数组的一些相关机制:
src/share/vm/interpreter/bytecodeInterpreter.cpp – 为解释器实现字节码指令,包括创建和访问数组的指令。然而,它是曲折而错综复杂的。
src/share/vm/c1/c1_RangeCheckElimination.cpp – 在从字节码编译为本机代码时执行一些巧妙的数组边界检查消除。
由于数组是语言和 VM 的核心功能,因此不可能指向任何一个源文件并说 "here, this is the class Array
code"。数组很特殊,实现它们的机制简直无处不在。
如果你想自定义一个数组的行为,你唯一能做的就是不直接使用数组,而是使用,subclass,或者写一个集合class内部包含数组。这使您可以完全自由地定义 class 的行为和性能特征。但是,在Java语言意义上,不可能使自定义class成为数组。这意味着您不能使其实现 []
运算符或可传递给需要数组的方法。
我可以覆盖 array
的任何方法吗?
例如toString()
或其他方法。
import java.lang.reflect.Method;
public class ArraysClassTest {
static int[] array = { 1, 2, 3, 1 };
public static void main(String[] args) {
Class<? extends int[]> class1 = array.getClass();
try {
Method method = class1.getMethod("toString");
} catch (NoSuchMethodException | SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
在Java中,所有数组(包括基本类型的数组)都以java.lang.Object
作为基数class。 (一方面,这是零长度数组的建模方式)。
尽管可以覆盖该基 class 中的任何方法,但 Java 本身指定了数组的形式。你不能干涉它:特别是你不能 extend
一个数组。
回答你的直接问题:不,你不能。
数组是一种 "compiler" 结构——编译器知道 String[] 的含义;并从中创建相应的字节码。只能创建数组对象,不能"new array classes"。或者除此之外,JVM 知道如何处理 "array using" 字节码指令。
换句话说:定义数组对象行为的源代码完全不受您的控制。数组只是做数组做的事;你没办法干涉它。
然后回答你隐含的问题为什么会这样:
有时候理解的东西并不多;但只需接受。问题是 Java 语言是在将近 20 多年前创建的;在某些时候,一些人做出了一些设计选择。他们中的许多人都很优秀;如果我们现在重做一些事情,其中一些可能已经得到处理。
例如,您会发现 Scala 有不同的处理数组的方式。但是对于java,事情就是这样;尤其是对于 "so core" 语言作为数组的东西,现在改变任何东西都没有意义。
您可以创建一个代理并使用它来代替原始对象
final int[] array = { 1, 2, 3, 1 };
Object proxy = Proxy.newProxyInstance(array.getClass().getClassLoader(), array.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
StringBuilder b=new StringBuilder("the array is");
for(int i:array)
b.append(" ").append(i);
return b.toString();
}
});
System.out.println(proxy.toString());
上面的输出是“数组是 1 2 3 1”。
您不能更改数组的任何功能。 JLS §10.7 Array Members 指定数组的每个成员:
The members of an array type are all of the following:
The
public
final
fieldlength
, which contains the number of components of the array.length
may be positive or zero.The
public
methodclone
, which overrides the method of the same name in classObject
and throws no checked exceptions. The return type of theclone
method of an array typeT[]
isT[]
.A clone of a multidimensional array is shallow, which is to say that it creates only a single new array. Subarrays are shared.
All the members inherited from class
Object
; the only method ofObject
that is not inherited is itsclone
method.
规范不允许以任何方式自定义此实现。例如,数组的 toString()
方法始终是从 Object
.
为了创建数组对象,编译器将三个指令之一发送到已编译的 Java bytecode: newarray
for primitives, anewarray
for reference types, or multinewarray
for all multidimensional arrays. In implementing those instructions, the virtual machine creates each array class as needed at runtime (JVMS §5.3.3 Creating Array Classes)。 VM 还为编译器定义了专用的字节码指令,用于获取和设置数组元素以及获取数组的长度。
如何 数组在 VM 中实现没有任何规定。它纯粹是一个实现细节,甚至 Java 编译器也不知道,也不关心。实际涉及的代码取决于您 运行 您的程序所在的虚拟机的风格、该 VM 的版本、OS 和 CPU 它 运行 所在的,以及VM 配置的任何相关运行时选项(例如,是否处于解释模式)。
快速浏览 OpenJDK 8 源代码会发现数组的一些相关机制:
src/share/vm/interpreter/bytecodeInterpreter.cpp – 为解释器实现字节码指令,包括创建和访问数组的指令。然而,它是曲折而错综复杂的。
src/share/vm/c1/c1_RangeCheckElimination.cpp – 在从字节码编译为本机代码时执行一些巧妙的数组边界检查消除。
由于数组是语言和 VM 的核心功能,因此不可能指向任何一个源文件并说 "here, this is the class Array
code"。数组很特殊,实现它们的机制简直无处不在。
如果你想自定义一个数组的行为,你唯一能做的就是不直接使用数组,而是使用,subclass,或者写一个集合class内部包含数组。这使您可以完全自由地定义 class 的行为和性能特征。但是,在Java语言意义上,不可能使自定义class成为数组。这意味着您不能使其实现 []
运算符或可传递给需要数组的方法。