OOP 多态和构造器执行顺序
在java的面试题中,对象的初始化顺序配合多态是一种常见考题!今天我就来详细的回顾一下!
类中一般包括这几个部分:
- 静态成员 包括静态的成员变量 静态代码块、
- 非静态的成员变量
- 构造函数 (其实也是一种静态方法,只不过static是隐式的)
- 静态方法和非静态方法
Java尽力保证,所有变量在使用前都能得到恰当的初始化
方法的局部变量 java以编译时错误的形式来贯彻这种保证;而对于类的成员变量,如果是基本数据类型都保证会有一个默认值,如果是引用类型,未被初始化则会被赋值为Null!
静态成员—–>成员变量(相互之间按照定义顺序)—–>构造器等任何方法
初始化对象时,并不会执行静态方法。静态方法直接通过类名进行访问
对象的创建过程
以Dog类为例
1.即使没有显示的指定static关键字,构造器实际上也是静态方法。因此,当首次创建类型为Dog的对象(构造器可以看成静态方法),或者Dog的静态方法/静态域首次被访问时,java解释器必须查找类路径,以定位Dog.class文件
2.然后载入Dog.class,有关静态初始化的所有动作(静态成员变量 静态代码块)都会执行。因此,静态初始化只在class对象首次加载的时候进行一次。
3.当用new Dog()创建对象的时候,首先在堆上为Dog对象分配足够的存储空间。
4.这块存储空间将会被清零,这就自动的将Dog对象中的所有基本数据类型都设置为默认值,而引用则被设置为null
5.执行父类的构造函数,依次递归直到继承层级的根。首先执行根,然后是下一层导出类,直到最近父类
5.执行所有出现于成员变量定义处的初始化操作
6.执行构造器本体
构造器与多态
基类的构造器总是在导出类的构造过程中被调用,并且按照集成的层次逐渐向上链接,以使每个基类的构造器都得以调用!
对复杂对象调用构造器的顺序:
1.首先调用基类的构造器。这个步骤会反复递归下去,首先是构造这种层次结构的根,然后是下一层的导出类,等等知道最底层的导出类,也就是最近父类
2.按照声明顺序调用成员的初始化方法
3.调用导出类构造器的本体
例子
- SomeThing.java
package OOP;
public class SomeThing {
public SomeThing() {
System.out.println("SomeThing 构造方法正在执行");
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- Person.java
package OOP;
public class Person extends SomeThing {
static{
System.out.println("Person 静态代码块正在执行");
}
public Person() {
System.out.println("Person 构造方法正在执行");
}
public void introduce(){
System.out.println("你好,我是一个Person");
}
//此方法只有Person有,未被覆盖
public void personShow(){
System.out.println("Welcome to Person's Show");
}
//静态方法
public static void SoLo(){
System.out.println("Person静态方法正在执行");
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- Student.java
package OOP;
public class Student extends Person {
//成员变量,声明处实例化
private StudentInfo info = new StudentInfo();
static {
System.out.println("Student 静态代码块正在执行");
}
public Student() {
System.out.println("Student 构造方法正在执行");
}
// 覆盖的方法
public void introduce() {
System.out.println("你好,我是一个Student");
}
public void studentShow() {
System.out.println("Welcome to Student's Show");
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- StudentInfo.java
package OOP;
public class StudentInfo {
public StudentInfo() {
System.out.println("正在执行 StudentInfo 构造器");
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- OOPdemo.java
package OOP;
public class OOPdemo {
public static void main(String[] args) {
//1.首先声明对象为Person类型,则Person中静态成员会被执行
//2.然后调用Student的构造函数,加载Student类,静态成员先执行
//3.调用Student的构造函数,默认先调用父类的构造函数,递归直到根
//4.调用Student的构造函数,先初始化Student的成员变量,基本类型赋默认值,
//引用类型未初始化赋值为NULL,有初始化操作则执行
//5.调用Student构造函数的本体
Person p=new Student();
System.out.println("p的类型---"+p);
//执行覆盖方法,执行子对象(实际对象)
p.introduce();
//执行父类方法,未覆盖
p.personShow();;
//因为是Person引用所以,student类中添加的方法,person对象不可见
//没有 p.studentShow()
((Student)p).studentShow();
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 执行结果