[英]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();
}
}
}
您不能更改数组的任何功能。 JLS§10.7 数组成员指定数组的每个成员:
数组类型的成员包括以下所有:
public
final
字段length
,其中包含数组的组件数。length
可以是正数或零。
public
方法clone
,它将覆盖Object
类中的同名方法,并且不引发任何检查异常。 数组类型T[]
的clone
方法的返回类型为T[]
。多维数组的克隆很浅,也就是说,它仅创建一个新数组。 子数组是共享的。
所有成员都继承自类
Object
; 不继承的Object
的唯一方法是其clone
方法。
该规范不允许以任何方式自定义此实现。 例如,数组的toString()
方法始终是从Object
继承的基本方法。
为了创建一个数组对象编译器发出一三指令到编译Java字节码 : newarray
为原语, anewarray
对于引用类型,或multinewarray
所有多维数组。 在实施这些指令时,虚拟机将在运行时根据需要创建每个数组类( JVMS§5.3.3 创建数组类 )。 VM还为编译器定义了专用字节码指令,以供编译器用于获取和设置数组元素以及获取数组的长度。
尚未说明如何在VM中实现阵列。 它纯粹是实现细节,甚至Java编译器也不知道或不在乎。 涉及的实际代码取决于您在其上运行程序的虚拟机的风格,该VM的版本,其运行的OS和CPU以及配置了VM的任何相关运行时选项(例如,是否处于解释模式)或不)。
快速浏览OpenJDK 8源代码会发现一些与阵列有关的机制:
src / share / vm /解释器/bytecodeInterpreter.cpp –为解释器实现字节码指令,包括用于创建和访问阵列的指令。 但是,它曲折而复杂。
src / share / vm / c1 / c1_RangeCheckElimination.cpp –从字节码编译为本机代码时执行一些巧妙的数组边界检查消除。
由于数组是语言和VM的核心功能,因此不可能指向任何一个源文件并说“这里是class Array
代码class Array
”。 数组是特殊的,实现数组的机制实际上遍地都是。
如果要自定义数组的行为,唯一可以做的就是不直接使用数组,而是使用,子类化或编写内部包含数组的集合类。 这样您就可以完全自由地定义类的行为和性能特征。 但是,就Java语言而言,使自定义类成为数组是不可能的。 这意味着您不能使其实现[]
运算符或不能传递给需要数组的方法。
在Java中,所有数组(包括原始类型的数组)都将java.lang.Object
作为其基类。 (一方面,这就是零长度数组建模的方式)。
尽管可以覆盖该基类中的任何方法,但是Java本身指定数组的形式。 您将无法对此进行干预:尤其是您无法extend
数组。
要回答您的直接问题:不,您不能。
数组是一个“编译器”构造-编译器知道String []的含义; 并从中创建相应的字节码。 您只能创建数组对象,而不能创建“新数组类”。 或除此之外,JVM知道如何处理“使用”字节码指令的数组。
换句话说:定义事物数组对象行为的源代码完全不受您的控制。 数组只是在做数组。 您无法干预。
并提出一个隐含的问题,为什么事情是这样的:
有时候没什么好了解的 ; 但仅仅是接受 。 事实是Java语言是在20年前左右创建的。 在某些时候,有些人做出了一些设计选择。 他们中的许多人都很棒。 如果我们现在重做一些事情,其中一些可能已经得到处理。
例如,您会发现Scala具有不同的数组处理方式。 但是对于Java来说,一切都保持不变。 尤其是对于那些作为数组“如此核心”的语言而言,如今改变任何一个都毫无意义。
您可以创建一个代理并代替原始对象使用它
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());
上面的输出是“ array is 1 2 3 1 ”。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.