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

时间:2014-12-16 12:42:04

标签: java arrays inheritance compilation

Java语言规范指定

  

在Java编程语言中,数组是对象(§4.3.1),是动态创建的,可以分配给Object类型的变量(§4.3.2)。可以在数组上调用类Object的所有方法。

因此,考虑到数组是对象 - 为什么Java设计者决定不允许继承和覆盖它,例如,toString()equals()

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

4 个答案:

答案 0 :(得分:35)

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

即使在最近的语言中,在数组(通常是地图)的语言级别具有快速结构也被视为战略目标。大多数人不喜欢数组的可继承对象的权重,当然在JVM像JIT一样推进之前没有人想要这个。

这就是为什么数组作为对象而不是设计为类实例("An object is a class instance or an array")的原因。具有覆盖阵列上的方法的能力几乎没有什么好处,当然也不足以抵消检查正确应用方法的需要(并且在我看来不是一个足以抵消的好方法)代码读取的难度增加,类似于覆盖运算符时发生的情况。)

答案 1 :(得分:16)

我遇到了 UNDER THE HOOD - Objects and arrays ,它解释了几乎所有关于JVM如何处理数组的知识。在JVM中,数组使用特殊的字节码处理,而不像我们熟悉的其他对象。

  

在JVM指令集中,实例化并访问所有对象   使用相同的操作码集,之外的数组。在Java中,数组是   完整的对象,和Java程序中的任何其他对象一样,   是动态创建的。数组引用可以在任何地方使用   调用Object类型的引用,并且Object的任何方法都可以   在数组上调用。然而,在Java虚拟机中,数组是   使用特殊字节码处理

     

与任何其他对象一样,数组不能声明为local   变量;只有数组引用才可以。数组对象本身始终   包含基本类型数组或对象数组   引用。如果声明一个对象数组,则会得到一个数组   对象引用。必须显式创建对象本身   使用new并分配给数组的元素。

数组是动态创建的对象,它们用作容纳(常量)相同类型对象的容器。它看起来像数组不像任何其他对象,这就是它们被区别对待的原因。

答案 2 :(得分:8)

我想指出这个article。似乎数组和对象遵循不同的操作码。我不能诚实地总结它,但是看起来,数组根本不被视为Objects,就像我们通常习惯的那样,因此它们不会继承Object方法。

对该帖子的作者给予全部学分,因为这是一篇非常有趣的读物,包括短片和短片。详细。


通过多个来源进一步深入研究这个主题后,我决定给出我以前答案的更精细版本。

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

<强>对象

Object实例化遵循一个简单的操作码new,它是两个操作数的组合 - indexbyte1&amp; indexbyte2。实例化后,JVM会将引用推送到此对象的stack。所有对象都会发生这种情况,无论其类型如何。


阵列:

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

  

newarray - 弹出长度,分配由atype指示的新类型的基本类型,推送新数组的objectref

在创建涉及原始数据类型的数组时使用

newarray操作码(byte short char int long float { {1}} double)而不是对象引用。

  

boolean - 弹出长度,分配由indexbyte1和indexbyte2指示的类的新对象数组,推送新数组的objectref

创建对象引用数组时使用

anewarray操作码

  

anewarray - 弹出维度数量的数组长度,分配由indexbyte1和indexbyte2指示的新的多维数组,推送新数组的objectref

分配多维数组时使用

multianewarray指令


Object 可以是类实例或数组。

Oracle Docs

获取
  

类实例由类实例创建表达式

显式创建

BUT

  

数组由数组创建表达式

显式创建

这与有关操作码的信息密切相关。数组不是开发为类接口而是由数组创建表达式显式创建,因此自然不会隐式地能够继承和/或覆盖{{1} }。

正如我们所看到的,它与数组可能包含原始数据类型的事实无关。在考虑了一些问题之后,遇到人们可能想要multianewarrayObject的情况并不常见,但仍然是一个非常有趣的问题,可以尝试回答。


资源:

Oracle-Docs chapter 4.3.1

Oracle-Docs chapter 15.10.1

Artima - UnderTheHood

答案 3 :(得分:2)

标准java库中有许多类不能子类化,数组不是唯一的例子。考虑StringStringBuffer或任何“原始包装”,例如IntegerDouble。 JVM基于在处理这些对象时知道这些对象的确切结构(例如,对基元进行拆箱或在字节级操作数组内存)进行优化。如果你可以覆盖任何东西,那就不可能了,并且会严重影响程序的性能。