class Fu{
int num;
Fu(){
num=10;
System.out.println(" A fu run");
}
Fu(int X){
System.out.println("B fun run"+X);
}
}
class Zi extends Fu{
int num;
Zi(){
//super();//调用的就是父类中的空参数的构造函数
//super();
System.out.println("C zi run"+num);
return;
}
Zi(int x){
System.out.println("D Zi run"+x);
}
}
public class One1 {
public static void main(String[] args) {
new Zi();
//打印的结果
//A fu run
//C zi run0
}
}
从上面代码运行结果可以看出。子类实例化之前,必须先实例化父类。
子父类中的构造函数——子类实例化过程
子父类中的构造函数的特点。
在子类构造对象时,发现,访问子类构造函数时,父类也运行了。
为什么呢?
原因:在子类的构造函数中第一行有一个默认的隐私语句。super();
子类的实例化过程:子类中所有的构造函数默认都会访问父类中的空参数的构造函数。
为什么子类实例化的时候要访问父类中的构造函数呢?
那是因为子类继承了父类,要获取到了父类中内容(属性),所以在使用父类内容之前,
要先看父类是如何对自己的内容进行初始化的。
所以子类在构造对象时,必须访问父类中的构造函数。
为要完成这个必须的动作,就在子类的构造函数中加入了super()语句。
如果父类中没有定义空参数构造函数,那么子类的构造函数必须用super明确调用
父类中哪个构造函数。同时子类构造函数中如果使用this调用了该类构造函数时,
那么super就没有了,因为super和this都只能定义在第一行,所以只能有一个,
但可以保证的是,子类中肯定会有其他的构造函数访问父类中的构造函数。
注意:super语句必须要定义在子类构造函数的第一行,因为父类的初始化动作要先完成。
public class Two1 {
/*
Two1(){
super();//只要我们创建一个类,这些东西就已经默认有啦。
return;//我们写的每一类都object 的子类
}
* */
}
内存解析
class Fu{
Fu(){
super();
show();
return;
}
void show(){
System.out.println("fu show");
}
}
class Zi extends Fu{
int num=8;
Zi(){
super();
//这是是分水岭
//-->通过super初始化父类内容时,子类的成员变量并未显示初始化,等super()父类初始化完毕后,
//才进行子类的成员变量显示初始化。
System.out.println("zi cons run..."+num);
return;
}
void show(){
System.out.println("zi show..."+num);
}
}
public class Three1 {
public static void main(String[] args) {
Zi z= new Zi();
z.show();
}
}
在内存中的运行过程。
1,在栈中main函数进栈,并产生z,
2,在方法区中开辟出两个空间分别是Fu,Zi空间
他们里面分别有自己的代码。其中Zi空间中super
会指向Fu的空间
3,在堆中,会有new Zi(),有一串地址产生指向z。
同时默认初始化num=0;
4,然后Zi()就会进栈,同时有一串的地址标识
然后运行到super();Fu()就会进栈,同时也会有一
串地址标识
5,Fu()里面也有super()指向object的空间,然后就会运行
show()这个方法,因为有地址标识,所以就会先在
Zi()的空间找,所以就会运行子类的show()方法『覆盖操作』,
子类的num还没有显示初始化,还是0。
然后就弹栈咯。
6。父类初始化完了,才会给子类进行显示初始化,才把num赋值为8
7.Zi()也弹栈啦,就会把产生的地址,赋值个z