数组是原始类型还是对象(或完全不同的东西)?

59
这个问题基本上是自我解释的。我没有找到数组的API(除了这个Arrays,但这只是定义了一堆静态帮助函数来处理实际的数组)。如果没有相应的类,这似乎表明数组不能是一个Object
然而,数组具有像length这样的公共字段以及可以调用的方法,如.equals().clone()似乎(非常强烈地)暗示了相反的结论。
原始数组的奇怪展示和行为的解释是什么?
需要注意的是,我刚才尝试在数组的.clone()方法上使用Eclipse的“打开实现”功能,希望能够查看该方法的定义方式和位置(因为它说明int[]从Object覆盖了它),但这实际上导致我的整个Eclipse崩溃了...
7个回答

70

每种数组类型都有一个对应的类,所以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[] 的子类型。


1
非常好的答案!我现在明白为什么找不到任何API或其他东西。这非常有趣,JVM会在运行时自己创建这些类。最后一个问题:如果数组像任何其他对象一样是类的成员,那么初始化是如何工作的?如果你所说的是准确的,[]只是类名的一部分,为什么它们不使用构造函数声明,即new int vs new int[2]? - asteri
1
最有可能的是在JVM中有特殊的代码来处理数组初始化,这与标准对象实例化有很大不同。 - Matt
不必影响语法选择。 - irreputable
1
请注意,编译时子类型规则会破坏类型安全。 - adam.r
你没有回答数组是否是一个对象。 - Arun Raaj
显示剩余2条评论

28

Java语言规范可以给你一个概念:

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

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

此外

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

因此,数组不是实例,所以您不需要使用构造函数来创建它们。相反,您可以使用数组创建表达式来创建它们。


也许我想太多了...但是如果一个东西既不是类也不是类的成员,它怎么能扩展“Object”呢? - asteri
1
@Jeff 我无法真正回答这个问题。也许这里可以帮助你。此外,这里还有一个有趣的答案链接 - Baz
@irreputable 您的意思是 int[].class 吗? - csguy

17

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

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

根据JLS 第4.3节,Java 语言中有四种引用类型:类类型(§8)、接口类型(§9)、类型变量(§4.4)和数组类型(§10)。

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

因此,根据第一条引用,Array其实不是一个类,而是另一种类型。但本质上,数组是对象,虽然不属于某个特定的Class,而是属于Array类型。所以它们并不是某个类的实例,而是定义为以这种方式创建的对象。


我知道。我以前用过数组。当意识到数组的行为与实际的常规对象有多么不同时,这个问题突然浮现在脑海中。例如,在您的“new”声明中,您不使用new int [2]()……因为它不是真正的构造函数。为什么?API在哪里?解释是什么?它并不像你所说的那么简单。 - asteri
2
我更愿意知道如果有人不喜欢我的回答,这样我就可以改进它,而不仅仅是看到它的负评。 - Rohit Jain

7
简而言之,是的,[] 是 Object 的一种类型。据我所知,它直接继承自 Object。它具有所有 Object 方法,如 toString()、hashCode() 等,以及一个特殊的暴露变量 length。java.util.Arrays 类是处理数组类型的实用程序类。当你把 int[] 这样的东西加入到混乱中时,就会有点混乱了:int[] 不继承自 Object[]。此外,与其他 Object 类型不同的是,数组类型没有构造函数。它们遵守 new 关键字,但通常是为了分配大小。这有点奇怪,但只是语言的一种怪癖。
回答问题,是的,它们是对象。

一个数组是一个对象...但是int[]并没有继承自Object?这让我很困惑。我也对构造函数的缺失感到困惑,因为我们使用new...这是怎么工作的?原始数组基本上是一个对象和硬连线原始类型之间的交叉吗? - asteri
1
不要误认为 int[] 继承自 Object[]。就像 int[] 和 Object[]、String[] 一样,它们都继承自 Object,而不是 Object[]。泛型有助于编写接受数组的方法,以及我提到的 Arrays 实用类,但是这种奇怪的怪癖有时会导致一些奇怪的代码,只是为了让类型对齐。 - Greg Giacovelli
2
[] 看作是类名的一部分。所以有原始类型 int,有 Object 类型的 Integer,还有另一种 Object 类型的 int[] - Greg Giacovelli
2
@Jeff 这里有一些信息[https://dev59.com/hEzSa4cB1Zd3GeqPkCle]。虽然问题针对的是二维数组,但那里的答案应该能让你对机制有所了解。 - Baz
啊,我明白了。我读你的帖子太快了。还有,谢谢你的链接,巴兹。 - asteri
显示剩余3条评论

3

1
我已经查看了那份文档,但它的API在哪里?这是我无法在任何地方找到的。 - asteri

0

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

更深入地了解,原始类型可以使用原始值存储在内存中,但对象是一个地址(引用)。因此,我们可以想象一个悖论,如果数组是原始类型,我们如何将原始值存储在内存中?我认为与String相同,但String是一个final对象,因此您可以像基本类型一样轻松构造一个对象,例如String s =“s”。



网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接