为什么是数组对象,但不能用作基类?

Java语言规范指定

在Java编程语言中,数组是对象(第4.3.1节),是dynamic创build的,可以分配给Objecttypes的variables(第4.3.2节)。 类Object所有方法都可以在数组上调用。

所以,考虑到数组是对象 – 为什么Javadevise者决定不允许从它inheritance和重写,例如toString()equals()

目前的语法不允许创build一个数组作为基类的匿名类,但我不认为是他们的决定的原因。

Java是非对象语言和当时非常慢的语言之间的妥协,一切都是对象(想想Smalltalk )。

即使在最近的语言中,在数组(通常是地图)的语言级别上具有快速结构也被认为是一个战略目标。 大多数人不喜欢数组的可inheritance对象的重量,在JVM像JIT一样进步之前,肯定没有人想要这样做。

这就是为什么作为对象的数组不是被devise为类实例( “一个对象是类实例或数组” )。 如果能够在数组上重写一个方法的能力是没有什么好处的,当然也不是一个足够好的方法来平衡需要检查正确的方法来应用(在我看来不是一个很好的方法 – 代码阅读的难度增加,类似于你重载操作符时发生的情况)。

我遇到了UNDER THE HOOD – 对象和数组 ,它解释了几乎所有你需要知道的有关JVM如何处理数组的东西。 在JVM中,数组由特殊的字节码处理,而不像其他我们熟悉的对象。

在JVM指令集中, 除了数组 ,所有对象都被实例化并访问,使用同一组操作码。 在Java中, 数组是完整的对象 ,并且像Java程序中的其他对象一样dynamic创build。 数组引用可用于调用Objecttypes的引用的任何位置,并且可以在数组上调用Object的任何方法。 然而,在Java虚拟机中, 数组由特殊的字节码处理

与任何其他对象一样,数组不能被声明为局部variables ; 只有数组引用可以。 数组对象本身总是包含基本types数组或对象引用数组。 如果你声明一个对象数组,你会得到一个对象引用的数组。 对象本身必须用new来显式创build并分配给数组的元素。

数组是dynamic创build的对象,它们充当容纳相同types的(常量)对象的容器。 它看起来像数组不像任何其他对象,这就是为什么他们被区别对待。

我想指出这篇文章 。 看起来好像数组和对象遵循不同的操作码。 我不能诚实地总结一下,不过看起来,数组并不是像我们通常习惯的那样被当作Objects ,所以它们不会inheritanceObject方法。

因为这是一个非常有趣的阅读,简短和详细的完整的信贷给该职位的作者。


进一步深入到多个来源的话题,我决定给我以前的答案更详细的版本。

首先要注意的是, 对象数组的实例化在JVM中非常不同,它们遵循各自的字节码。

目的:

Object实例化遵循一个简单的Opcode new ,它是两个操作数的组合 – indexbyte1indexbyte2 。 一旦实例化,JVM将对该对象的引用推入stack 。 对于所有对象都会发生这种情况,不论其types如何。


arrays:

Array操作码(关于数组的实例化)被分成三个不同的代码。

newarray – popup长度,分配由atype指定的types的原始types的新数组,推新数组的objectref

在创build涉及基本数据types( byte short char int long float double boolean )而非对象引用的数组时,使用newarray opcode。

anewarray – popup长度,分配由indexbyte1和indexbyte2指示的类的一个新对象,推送新数组的objectref

在创build对象引用数组时使用了anewarray操作码

multianewarray – popup数组长度的数量,分配一个由indexbyte1和indexbyte2表示的新的multidimensional array,并推入新数组的objectref

在分配multidimensional array时使用multianewarray指令


对象可以是一个类实例或一个数组。

从Oracle Docs中获取

类实例是由类实例创buildexpression式显式创build的

数组由数组创buildexpression式显式创build

这与关于操作码的信息是一致的。 数组根本不是被开发成类接口,而是由数组创buildexpression式显式创build的,因此自然不会隐式地inheritance和/或重写Object

正如我们所看到的,它与数组可能保存原始数据types无关。 尽pipe如此,在遇到可能想要toString()equals()但是仍然是一个非常有趣的问题的情况下,尝试和回答并不常见。


资源:

Oracle-Docs章节4.3.1

Oracle-Docs章节15.10.1

Artima – UnderTheHood

标准java库中有许多类不能进行子类化,数组并不是唯一的例子。 考虑一下String ,或者StringBuffer ,或者任何“原始包装器”,比如Integer或者Double 。 JVM在处理这些对象时会根据这些对象的确切结构进行优化(比如拆箱或者在字节级操作数组内存)。 如果你能覆盖任何东西,这是不可能的,并且非常严重地影响程序的性能。