数组是原始类型还是对象(或完全是其他东西)?

Posted

技术标签:

【中文标题】数组是原始类型还是对象(或完全是其他东西)?【英文标题】:Is an array a primitive type or an object (or something else entirely)? 【发布时间】:2012-09-30 04:19:37 【问题描述】:

这个问题基本上是不言自明的。我还没有找到数组的 API(除了这个Arrays,但这只是定义了一堆用于处理实际数组的静态辅助函数)。如果它没有类,这似乎表明数组不能是Object

然而,数组具有像 length 这样的公共字段以及像 .equals().clone() 这样可以调用的方法这一事实似乎(非常强烈地)暗示了完全相反的情况。

原始数组的奇怪表示和行为的解释是什么?

作为说明,我刚才尝试在数组的.clone() 方法上使用“Open Implementation” Eclipse 功能,希望我能够查看该方法的定义位置和方式(因为它说int[] 从 Object 中覆盖它),但它实际上导致我的整个 Eclipse 冻结并崩溃......

【问题讨论】:

【参考方案1】:

请看下面的代码。它编译:

    int[] arr = new int[2];
    System.out.println(arr.toString());

现在,在任何原始类型上,您都不能调用 Object 类中定义的方法(toString())(或者,任何与此相关的方法)...因此,数组本质上是 Object

好的,给你:

来自JLS Section 4.3:

有四种引用类型:类类型(第 8 节)、接口 类型(第 9 节)、类型变量(第 4.4 节)和数组类型(第 10 节)。

还有,Section 10:

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

所以,从第一句话来看,Array 实际上并不是一个类……它是另一种类型。但是,数组本质上是对象,虽然不是某些Class,但它们是Array 类型。所以它们不是某个类的实例,可能是array 的对象被定义为以这种方式创建...

【讨论】:

我知道。我以前用过数组。当意识到数组的行为与实际的常规对象有何不同时,这个问题就浮现在脑海中。例如,在您的“新”声明中,您不使用 new int[2]()... 因为它不是真正的构造函数。为什么? API在哪里?解释是什么?它没有你做的那么简单。 而且我更愿意知道是否有人不喜欢我的回答,以便我可以改进它,而不是仅仅看到它的反对意见..【参考方案2】:

每个数组类型都有一个类,所以int[] 有一个类,Foo[] 有一个类。这些类是由 JVM 创建的。您可以通过int[].classFoo[].class 访问它们。这些类的直接超类是Object.class

public static void main(String[] args)

    test(int[].class);
    test(String[].class);


static void test(Class clazz)

    System.out.println(clazz.getName());
    System.out.println(clazz.getSuperclass());
    for(Class face : clazz.getInterfaces())
        System.out.println(face);

还有一个编译时子类型规则,如果AB 的子类型,A[]B[] 的子类型。

【讨论】:

优秀的答案!我现在明白为什么我现在找不到任何 API 或任何东西了。非常有趣的是 JVM 在运行时自己生成这些类。最后一个问题:如果数组是一个类的成员,就像任何其他对象一样,初始化是如何工作的?如果你说的是准确的并且 [] 只是类名的一部分,为什么不使用构造函数声明它们,即 new int[](2) vs new int[2]? int[2] 语法来自 C,Java 试图接近。 jvm 中很可能有特殊代码来处理数组初始化,这与标准对象实例化完全不同。 我就是这么想的。所以“在幕后”,编译器是提取数字并将其传递给它制作的标准构造函数,还是什么? 请注意,编译时子类型化规则破坏了类型安全***.com/a/3712419/2558896【参考方案3】:

只有我们所知道的 Java 中的这几种原始类型。基本上,我们仍然需要几个步骤来创建一个数组,例如声明、构造或根据需要进行初始化,这意味着数组确实是一个对象。

更深入一点,原始类型可以与原始值一起存储在内存中,但对象是地址(引用)。所以我们可以想象一个悖论,如果数组是原始类型,我们如何将原始值存储在内存中?我觉得和String一样,但是String是final对象,所以可以很简单的构造一个对象,String s = "s",就像原始类型一样。

【讨论】:

【参考方案4】:

如此简短,是的,[] 是Object 的一个类型。据我了解,它直接从Object 扩展而来。上面有所有的 Object 方法,toString()hashCode(),...加上一个特殊的暴露变量,称为lengthjava.util.Arrays 类是用于处理数组类型的实用程序类。当您添加诸如 int[] 不继承自 Object[] 之类的混乱时,这有点令人困惑。此外,与其他 Object 类型不同,数组类型没有构造函数。他们尊重new 关键字,但这通常是为了分配大小。这有点奇怪,但只是其中一种语言怪癖。

不过,要回答这个问题,是的,它们是一个对象。

【讨论】:

一个数组是一个对象...但是 int[] 不继承自 Object?这让我很困惑。而且我也对没有构造函数感到困惑,因为我们使用new...这是如何工作的?基元数组基本上是对象和硬连线基元之间的交叉...? no int[] 不继承自 Object[]。与 int[] 和 Object[] 一样,String[] ... 都不同,因为它们都继承自 Object,而不是 Object[]。泛型有助于编写采用数组的方法,以及我提到的 Arrays 实用程序类,但是是的,这个奇怪的怪癖会导致一些时髦的代码,有时只是为了让类型对齐 如果 int[] 不继承自 Object 并且 int[] 不是原语,它是什么? Java 的主要格言(所有对象都扩展Object)是否不完全正确,并且数组属于单独的对象类别? [] 视为类名的一部分。所以有int 这是原始的。有Integer,这是一个Object。还有int[],这是Object的另一种类型。 @Jeff 有一些信息here。虽然这个问题针对的是二维数组,但那里的答案应该能让您对机制有所了解。【参考方案5】:

Java Language Specification 应该会给你一个想法:

数组类型的直接超类是Object。

每个数组类型都实现了接口Cloneablejava.io.Serializable

Moreover:

对象是类实例或数组。

所以数组不是实例,因此您不需要构造函数来创建它们。相反,您使用Array Creation Expressions。

【讨论】:

也许我想太多了...但是不是类或类成员的东西怎么能扩展Object @Jeff 我无法真正回答这个问题。也许this 有帮助。此外,还有一个有趣的答案here。 @irreputable 你的意思是 int[].class【参考方案6】:

数组是一个容器对象,包含固定数量的单一类型值。

见http://docs.oracle.com/javase/tutorial/java/nutsandbolts/arrays.html

【讨论】:

我看过那个文档,但是它的 API 在哪里呢?那是我在任何地方都找不到的。【参考方案7】:

这是一个对象

http://docs.oracle.com/javase/tutorial/java/nutsandbolts/arrays.html

【讨论】:

以上是关于数组是原始类型还是对象(或完全是其他东西)?的主要内容,如果未能解决你的问题,请参考以下文章

什么是int?int和Integer有什么区别?

数组的四个基本特点

将对象数组转换为其原始类型的数组

每天做点面试题

如何在 WebMethod 中接收非原始数据?

javaScript面向对象