初学者对象混淆数组

时间:2018-02-17 09:51:50

标签: java arrays oop polymorphism

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

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类型的引用变量组成。如果这是真的,那么第一个错误是有意义的,因为我不能有一个引用超类型的子类型。

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

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

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

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

3 个答案:

答案 0 :(得分:15)

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

在您的代码中,编译时x的类型为Type1[]。那就是编译器认为的那样。在运行时,x的类型为Type2[],但编译器不知道。

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

但第二个错误发生在编译时,因为编译器仍然认为x的类型为Type1,并且method2中没有名为Type1的方法,甚至虽然x实际上在运行时持有Type2[]

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

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

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

Superclass[] array = new Subclass[2];

你会让自己陷入困境。

答案 1 :(得分:6)

超类型引用可以引用子类型。我想你明白这一点,因为第一个错误与你有关。

第二个错误源于这样一个事实:在编译时,x仍然是Type1[]。这意味着在运行时,引用可以包含任何子类型,包括不具有方法method2的类型。这就是为什么您只能使用Type1中定义的方法。

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

答案 2 :(得分:0)

将其用于以下代码的外行术语,

Type1[] x = new Type2[2];

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

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

这里x是参考变量。我们正在创建一个" Type2"并且x具有Object Type2的引用 [简单地说,x是指向Type2对象的远程控制] 。别忘了,x属于' Type1',这意味着它没有' method2()'遥控器上的按钮。[记住,方法2是Type2 Class而不是Type1]。

编译器调用对象上的方法,只有当它在类中看到它时才会调用它。编译器不关心你正在创建哪个Object [ here :new Type2],它关心的是你正在进行调用的人( here:x [1],类型为Type1 )。因此,它会抛出编译时错误。它不会打扰在运行时发生的事情或它指向的对象,它关心的是引用类型是否具有调用方法[在我们的术语中,遥控器是否具有该按钮< / EM>]吗

  

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

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

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

正如你所说,你对这些东西不熟悉,这是我对你的参考。

参考:

Head First Java