为什么允许使用子类的构造函数实例化父类对象?

4

请考虑以下内容:

public class parent {
    int x;

    parent() {
        x = 5;
    }

}

public class child extends parent {
int y;

child() {
    super();
    y = 10;
}

public static void main(String[] args) {

    parent p = new child();
    System.out.println(p.y);//can't access variable y
}

在父类对象中调用了子类的构造函数。在进行Android编程时,我经常遇到这种情况。

我的问题是为什么允许这样做?子类的构造函数可能会初始化其他成员,但是像上面的例子中一样,它们的蓝图可能没有在父类中定义。


提示:对象“p”的类型及其基本类型是什么?接下来,“y”在“child”类中被声明。 - SatyaTNV
这里在父类对象上调用了子类的构造函数。不,你定义了一个类型为“child”的对象,但是你的其余代码将它视为“parent”对象。 - Smutje
希望你有一本字典,可以查找“extend”的含义。在这个上下文中(child extends parent),它意味着子类拥有父类所有的东西,再加上一些自己的字段和方法。 - laune
注意:在Java中,压倒性的惯例是大写类名,例如Parent而不是parent,以及Child而不是child。您不必在自己的代码中遵循惯例,但是遵循惯例非常有用,并且在与他人共享代码时遵循惯例非常有用(例如在此处提问时)。 :-) - T.J. Crowder
4个回答

20

为什么允许使用子类的构造函数来实例化父类对象?

实际上并不是这样。在这一行代码中:

parent p = new child();

...你正在创建一个child对象,而不是parent对象。你用来引用它的变量p的类型为parent,这意味着你只能通过该引用使用parent的东西,但该对象是一个child对象。该对象确实有一个y,但你无法通过p访问它。你可以通过以下方式查看:

parent p = new child();
System.out.println( ((child)p).y );

通过告诉编译器,我们知道p虽然是parent类型,但它指向child(通过“强制转换”),我们可以访问它的child特定部分。(当你有替代方案时,这不是一个好的做法。)

在对象导向编程中,“多态性”(即能够在约束条件下引用某个对象,但它实际上代表的是另一个对象)是一种重要的概念。

举个例子:

class Animal {
}

class Dog extends Animal {
}

class Cat extends Animal {
}

所有的Dog都是Animal,所有的Cat也是如此,但是Dog不是Cat。假设你经营一家宠物店,并想要存储你手头上拥有的动物清单:

List<Animal> animals;

这些条目可以是Animal类型的对象,或其任何子类型,例如DogCat。这使您可以在Animal上拥有动物的共同方面,然后只在这些类型上拥有Dog-或Cat- 特定方面(属性或行为)。您可以遍历Animal列表并以动物性质运行它们,而不必担心它们是Dog还是Cat


5

除了在构造函数中实例化子类child时,没有对父类进行实例化。在这里,您得到一个实例,即child的实例。

允许对parent p进行赋值,因为每个child对象也是parent对象。

将一个child对象分配给其父类类型的变量使您能够编程到类的接口,限制了child类的使用仅限于其父类的方法。这为您提供了更改实现的灵活性:

Parent p = new OtherChild();

这样,使用p的代码就不需要知道它正在访问ChildOtherChild对象。

2
当你写parent p = new child();时,实际上创建了子类对象。当它调用子类构造函数时,通过super()调用首先调用超类构造函数。

1
因为孩子也是父母,所以它可以获得其类型。但是,对象将是一个孩子。因此,类型为Parent的Child对象。
注意:类名大写。

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