为什么是数组对象,但不能用作基类?
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
,它是两个操作数的组合 – indexbyte1
和indexbyte2
。 一旦实例化,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在处理这些对象时会根据这些对象的确切结构进行优化(比如拆箱或者在字节级操作数组内存)。 如果你能覆盖任何东西,这是不可能的,并且非常严重地影响程序的性能。