【问题标题】:Beginner Array of Objects Confusion对象数组的初学者混淆
【发布时间】:2018-07-28 03:28:15
【问题描述】:

当我在以下代码中声明数组时,我无法理解实际发生的情况。

class Type1 {

}

class Type2 extends Type1 {
    public void method2() {

    }
}

class Test {
    public static void main(String[] args) {

        Type1[] x = new Type2[2];
        x[0] = new Type1(); // runtime error
        x[1] = new Type2();
        x[1].method2(); // syntax error

    }
}

我认为由于数组声明的右侧是new Type2[2],因此该数组将包含Type2 类型的引用变量。如果这是真的,那么第一个错误是有道理的,因为我不能有一个引用超类型的子类型。

但是,为什么第二个错误在那之后出现了两行? method2()不是Type2知道的,所以方法是引用变量知道的吗?似乎是因为Type1 不知道method2,所以这是否意味着数组包含Type1 类型的引用变量?如果这是真的,为什么会出现第一个错误,因为它不再是引用超类型的子类型?

另外,为什么第一个错误是运行时错误,而另一个是语法错误?

请注意,我只是在上我的第二门编程课程,所以我的术语可能有点偏离。

编辑:问题here 没有回答我的问题,因为它没有回答为什么像x 这样的数组元素不能调用method2(),即使Type 2x 的元素也是如此。我的问题因此而不同,因为我的问题还问为什么在第二个错误也发生时会发生第一个错误(为什么x 的元素不能引用Type1 类型的对象并且同时不能调用method2())。我原本以为,如果一个错误发生了,那么另一个错误就不会发生。我想要两个错误之间的比较,以及比简单的多态性规则更深入的解释。

【问题讨论】:

标签: java arrays oop polymorphism


【解决方案1】:

这是 Java 允许您做的那些奇怪的事情之一,将派生类的数组分配给基类的数组变量。

在您的代码中,编译时的xType1[] 类型。这就是编译器所认为的。在运行时,x 的类型为 Type2[],但编译器不知道这一点。

第一个错误发生在运行时,因为正如您所说,您不能将Type1 分配给Type2 类型的变量。

但是第二个错误发生在编译时,因为编译器仍然认为x的类型是Type1,并且Type1中没有调用method2的方法,即使x实际上持有一个@ 987654332@ 在运行时。

要调用method2,您需要通过强制转换告诉编译器x[1] 的类型为Type2

((Type2)x[1]).method2();

今天的课程?不要这样做:

Superclass[] array = new Subclass[2];

你会惹上麻烦的。

【讨论】:

  • x 在编译时是 Type1[] 类型。这就是编译器所认为的。在运行时,x 是 Type2[] 类型,但编译器不知道。 +1
  • @Sweeper 为板块添加协方差,使其更加混乱
【解决方案2】:

超类型引用可以引用子类型。我想你明白这一点,因为第一个错误对你来说是连贯的。

第二个错误源于在编译时x 仍然是Type1[]。这意味着在运行时引用可以包含任何子类型,包括没有方法method2 的类型。所以只能使用Type1中定义的方法。

例如,您可以在运行时使用isInstanceOf 检查类型是否实际上是Type2,然后将其转换为Type2,然后使用method2。 不过,通常有更好的解决方案。

【讨论】:

    【解决方案3】:

    以下代码通俗地说,

    Type1[] x = new Type2[2];
    

    让我们只使用Type1 x = new Type2;不是数组,而是类。

    您从上述步骤中推断出什么?

    这里的 x 是一个参考变量。我们正在创建一个“Type2”对象,x 具有 Object Type2 的引用[可以说,x 是一个指向 Type2 对象的遥控器]。别忘了,x 属于 'Type1' 类型,这意味着它的遥控器上没有 'method2()' 按钮。[记住,method2 属于 Type2 类而不是 Type1]。

    编译器调用对象的方法,只有当它在类中看到它时。编译器不关心你正在创建哪个对象 [here: new Type2],它只关心你正在调用谁(here: x[1],它的类型是 Type1 )。因此,它会引发编译时错误。它不关心运行时发生了什么或它指向哪个对象,它只关心引用类型是否有调用方法[在我们的术语中,遥控器是否有那个按钮]?.

    为什么第一个错误是运行时错误,而另一个是语法 错误?

    我希望上述解释(当您根据您的问题考虑数组类型时)回答您问题的后半部分。

    而且,至于第一部分,您几乎已经回答了。无论如何,数组允许这种东西并在运行时爆炸,而 Arraylist 在编译时这样做。[这是泛型的一部分]。

    正如你所说,你是这个东西的新手,这是我给你的参考。

    参考:

    Head First Java

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-08-13
      • 2022-11-22
      • 1970-01-01
      • 1970-01-01
      • 2012-01-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多