这样一个例子:
class Animal
{
Animal()
{
System.out.println("Animal's constructor");
}
}
class Mankind extends Animal
{
Mankind()
{
System.out.println("Mankind's constructor");
}
}
public class Kids extends Mankind
{
Kids()
{
System.out.println("Kids' constructor");
}
public static void main(String[] args)
{
Kids someKid=new Kids();
}
}
为什么运行结果是:Animal's constructor
Mankind's constructor
Kids' constructor
难道在创建Kids的实例对象的时候,还调用了Kids的父类Animal和Mankind的构造方法 ?
那是不是也创建了Animal和Mankind的对象,只不过因为没有引用指向它们所以又被java的
“垃圾自动回收”机制回收了???没有,在创建一个子类对象时,并不创建对象,创建对象是要用new的啊。子类的构造器先调用父类的无参数父类构造器,除非你在构造器中显示调用了父类的某个构造器。调用构造函数的意义:
子类继承父类,一种是把父类属性继承下来,然后调用父类的构造函数来初始化这些属性,直致所有这些继承下来属性都初始化完毕(即所有父类的构造函数都被调用),这样解释的话,当然不会构造父类对象! 因为这些构造函数的调用是为了初始化从父类继承下来的属性,被初始化的属性 的地址始终在本对象当中,虽然会出现 象 构造父类对象的现象,但那只是子类实例化的一个过程,并非实际上生成父类对象。
打个比喻,或许你更能明白: 人类出生之前的十个月,会出现象哺乳动物的特征(胎儿在一个月时最象,到第十个月时,就完全是人了),你不能说,在形成人的过程当中,就要先生出一个哺乳动物,然后再生出一个人吧。
希望你能明白这个比喻! Thinking in Java 第六章中说得很明白:
创建衍生类的一个对象时,它在其中包含了基础类的一个“子对象”。这个子对象就象我们根据基础类本身创建了它的一个对象。从外部看,基础类的子对象已封装到衍生类的对象里了。
当然,基础类子对象应该正确地初始化,而且只有一种方法能保证这一点:在构建器中执行初始化,通过调用基础类构建器,后者有足够的能力和权限来执行对基础类的初始化。在衍生类的构建器中,Java会自动插入对基础类构建器的调用。下面这个例子向大家展示了对这种三级继承的应用:
//: Cartoon.java
// Constructor calls during inheritance
class Art {
Art() {
System.out.println("Art constructor");
}
}
class Drawing extends Art {
Drawing() {
System.out.println("Drawing constructor");
}
}
public class Cartoon extends Drawing {
Cartoon() {
System.out.println("Cartoon constructor");
}
public static void main(String[] args) {
Cartoon x = new Cartoon();
}
} ///:~
该程序的输出显示了自动调用:
Art constructor
Drawing constructor
Cartoon constructor
可以看出,构建是在基础类的“外部”进行的,所以基础类会在衍生类访问它之前得到正确的初始化。
即使没有为Cartoon()创建一个构建器,编译器也会为我们自动合成一个默认构建器,并发出对基础类构建器的调用
分享到:
相关推荐
程序中描述了子类对象构建调用父类的构造方法,以及类变量和实例变量创建的不同过程
20.7 在创建子类实例时,会创建父类实例,先创建哪个? 23 20.8 在子类构造方法中如何调用父类构造方法? 23 20.9 super关键字 24 20.10 父类中私有属性和私有方法可以继承吗? 24 20.11 在代码开发时先开发父类还是...
因此,在创建子类对象时,为了初始化从父类继承来的数据成员,系统需要调用其父类的构造方法。 如果没有显式的构造函数,编译器会给一个默认的构造函数,并且该默认的构造函数仅仅在没有显式地声明构造函数情况下...
:以员工为父类,该类包含员工的基本信息:姓名、年龄、部门。创建两个子类
* 执行启动类的main函数 -> 创建对象的继承树从高到底的类层次中的静态块(如果已经被执行过,则不会重复执行) -> * 继承树中的从最高层开始的实例语句块{}、然后对应的构造函数、以及构造函数中调用的方法 * ...
因此,在创建子类对象时,为了初始化从父类中继承来的成员变量,编译器需要调用其父类的构造函数。如果子类的构造函数没有显示地调用父类的构造函数,则默认调用父类的无参构造函数,至于什么事显式调用,在下面会...
对初学者非常有用的资源,大家拿回去好好看啊
在面向对象的方法里, 继承是指在基于现有的类创建新类时, 新类继承了现有类 里的方法和属性。 此外, 可以为新类添加新的方法和属性。 我们把新类称为现有 类的子类,而把现有类称为新类的父类。 一个子类的成员...
面向对象(Object-Oriented,简称 OOP)是一种程序设计范式,它以对象为中心,将数据和操作封装在一起,以实现...子类可以扩展或修改从父类继承的行为,同时也可以拥有自己的特定行为。继承是面向对象编程中实现代码重
java 面向对象设计 创建类 继承 封装 子类父类各种程序实例
构造函数不能是虚函数,因为在调用构造函数创建对象时,构造函数必须是确定的,所以构造函数不能是虚函数。析构函数可以是虚函数。1.父类Father.h: 代码如下:#pragma onceclass Father{public: Father(void); ...
子类继承父类以后,当子类创建对象时先调用父类的构造函数再调用子类的构造函数,删除对象时先调用子类的析构函数再调用父类的析构函数。 关于函数的覆盖和虚函数的解释可以参考工程中的Main实例 当父类中某函数被...
所以在调用这些方法时要传入不同的参数值. 成员变量和局部变量 •成员变量指的是在类范围里定义的变量;局部变量指的是在一个方法内定义的变量。 •不管是成员变量还是局部变量都遵守相同的命名规则。 •...
子类的对象使用这个方法时,将调用子类中的定义,对它而言,父类中的定义如同被"屏蔽"了。如果在一个类中定义了多个同名的方法,它们或有不同的参数个数或有不同的参数类型,则称为方法的重载(Overloading)。...
面向对象编程最基本特征是类和实例。...方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。实例化:创建一个类的实例,类的具体对象。
16.编写一个类A,该类创建的对象可以调用方法f 输出英文字母表,然后再编写一个该类的子类B,要求 ...在应用程序的主类中分别使用父类和子类创建对象,并分别调用方法f 计算两个正整数的最大公约数 和最小公倍数。
抽象类里可以包含构造器,抽象类里的构造器并不是用于创建对象,而让其子类调用这些构 造器来完成属于抽象类的初始化操作。 •接口里不能包含初始化块,但抽象类则完全可以包含初始化块。 •一个类最多只能有一个...
本文档包含内容:课程设计完整工程代码+数据库备份(.mdf格式),不含课程设计说明文档,绝无二次收费,看好了,绝无二次收费。
1. 从存储空间角度,虚函数对应一个指向vtable虚函数表的指针,这大家都知道,可是这个指向vtable的指针其实是存储在对象的内存空间的。问题出来了,如果构造函数是虚...而构造函数是在创建对象时自动调用的,不可能通