【问题标题】: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 冻结并崩溃......

【问题讨论】:

    标签: java arrays object primitive


    【解决方案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[].class、Foo[].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);
    }
    

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

    【讨论】:

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

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

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

    【讨论】:

      【解决方案4】:

      如此简短,是的,[] 是Object 的一个类型。据我了解,它直接从Object 扩展而来。上面有所有的 Object 方法,toString(),hashCode(),...加上一个特殊的暴露变量,称为length。 java.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。

      每个数组类型都实现了接口Cloneable 和java.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】:
      猜你喜欢
      • 2015-10-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多