繁体   English   中英

JVM如何实现数组的类?

[英]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源代码会发现一些与阵列有关的机制:

由于数组是语言和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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM