过程设计思想:
因:变量为方法所用
果:所以先初始化变量,再次初始化方法。
两种情况:
1.无继承
根据设计思想,
静态变量->静态方法->静态代码块->变量->方法->构造方法
2.有继承
有父类情况下的初始化
假设: Dog extends Animal
1、执行第一步,找出 Dog.class 文件,接着在加载过程中发现他有一个基类(通过 extends 关键字),于是先执行 Animal 类的第一二步,加载其静态变量和方法,加载结束之后再加载子类 Dog 的静态变量和方法。
如果 Animal 类还有父类就以此类推,最终的基类叫做根基类。
注意:因为子类的 static 初始化可能会依赖于父类的静态资源,所以要先加载父类的静态资源。
2、接着要 new Dog 对象,先为 Dog 对象分配存储空间 -> 到 Dog 的构造函数 -> 创建默认的属性。这里其构造函数里面的第一行有个隐含的 super(),即父类构造函数,所以这时会跳转到父类 Animal 的构造函数。
Java 会帮我们完成构造函数的补充,Dog 实际隐式的构造函数如下:
3、父类 Animal 执行构造函数前也是分配存储空间 -> 到其构造函数 -> 创建默认的属性 -> 发现挖槽我已经没有父类了,这个时候就给它的默认的属性赋值和方法的初始化。
4、接着执行构造函数余下的部分,结束后跳转到子类 Dog 的构造函数。
5、子类 Dog 对默认属性和方法分别进行赋值和初始化,接着完成构造函数接下来的部分。
一、为什么要执行父类 Animal 的构造方法才继续子类 Dog 的属性及方法赋值?
因为子类 Dog 的非静态变量和方法的初始化有可能使用到其父类 Animal 的属性或方法,所以子类构造默认的属性和方法之后不应该进行赋值,而要跳转到父类的构造方法完成父类对象的构造之后,才来对自己的属性和方法进行初始化。
这也是为什么子类的构造函数显示调用父类构造函数 super() 时要强制写在第一行的原因,程序需要跳转到父类构造函数完成父类对象的构造后才能执行子类构造函数的余下部分。
。
二、为什么对属性和方法初始化之后再执行构造函数其他的部分?*
因为构造函数中的显式部分有可能使用到对象的属性和方法。
Tips:其实这种初始化过程都是为了保证后面资源初始化用到的东西前面的已经初始化完毕了。很厉害,膜拜 Java 的父亲们。
说了这么多还是来个例子吧。
这里注意 main 函数也是一个静态资源,执行 Dog 类的 main 函数就是调用 Dog 的静态资源。
class JzfKnowledgeApplicationTests extends father{
private int num;
public JzfKnowledgeApplicationTests() {
super();
System.out.println("son方法打印:"+num);
a();
}
public void a(){
System.out.println("son构造方法");
}
{
System.out.println("son代码块");
num=1;
System.out.println("son代码块:"+age);
}
public static void main(String[] args) {
JzfKnowledgeApplicationTests jzfKnowledgeApplicationTests = new JzfKnowledgeApplicationTests();
}
}
public class father {
int age;
public father() {
age=18;
System.out.println("father构造方法");
this.fathera();
}
public void fathera(){
System.out.println("father方法"+age);
}
}
[外链图片转存失败,源站可能有防盗在这里插入!链机制,建描述]议将图片上https://传(imblog.snimg.cn/pCWM67208067ab03465a652b719dbca3.pngb39)(https:/`/img-blog.csdnimg.cn/67208067ab034654a652b71a9b9dbca3.png)]
继承流程:
①子类静态属性方法->子类静态方法->父类静态属性方法->
②子类调用构造器super()->父类属性->父类初始化方法->初始化父类结束->
③初始化子类属性->初始化子类方法->继续执行子类构造方法代码->子类初始化完成