可能学过java的人都应该知道类的继承,子类总是先执行父类的构造方法,然后再执行本类的构造方法来实例化对象,下面我们先来看一个例子来体现这一规则:
1class Test 2{ 3 public static void main(String[] args) 4 { 5 B b = new B(); 6 } 7} 8// 父类 9class A 10{ 11 public A() 12 { 13 System.out.println("父类的构造函数..."); 14 } 15} 16// 子类 17class B extends A 18{ 19 public B() 20 { 21 System.out.println("本类的构造函数..."); 22 } 23}
大家一定会想,这么简单的一个程序算什么呢,大家应该都能分析出来答案了
1父类的构造函数... 2本类的构造函数...
这就反映了先父类的构造->本类的构造的执行顺序;
那现在大家再用这个思路来分析这个看似简单,实际暗藏了些许陷阱的几十行代码:
1class Test 2{ 3 public static void main(String[] args) 4 { 5 A a = new B(); 6 } 7} 8 9class A 10{ 11 int age = 11; 12 { 13 System.out.print(age + " "); 14 age = 22; 15 System.out.print(1 + " "); 16 } 17 18 public A() 19 { 20 System.out.print(2 + " "); 21 printAge(); 22 } 23 24 public void printAge() 25 { 26 System.out.print(this.age + " "); 27 } 28} 29 30class B extends A 31{ 32 int age = 3;// {}初始化块 33 { 34 System.out.print(3 + " "); 35 } 36 37 public B() 38 { 39 System.out.print(4 + " "); 40 printAge(); 41 } 42 43 public void printAge() 44 { 45 System.out.print(this.age + " "); 46 } 47}
大家先来分析一下上面这个代码会输出什么?
首先我们先来看看正确的输出结果,再来分析其缘由;正确的结果如下:
11 1 2 0 3 4 3
怎么样,大家分析结果正确了吗?或者是否会对这个结果有怀疑呢,不用怀疑,将这个程序段复制运行一下你将会看到这个可爱的结果了;
那为什么结果是这样呢?现在我就带大家一起来分析一下这段代码,分析完之后你将会对 对象实例化顺序有一个新的认识;
分析之前我先大家说一下对象实例化的几个基本顺序:
- 给父类和子类的成员变量分配内存空间,并初始化值(这里涉及基本数据类型的默认值的知识,在这里就不细说了);
- 执行父类的成员变量声明和初始化块(顺序执行)
- 执行父类的构造函数(具体执行哪个构造函数是由子类的构造函数决定的)
- 执行子类的成员变量声明和初始化块(也是顺序执行)
- 最后才是子类的构造函数的执行
好了,现在我们顺着这个步骤来分析一下这段代码,你清楚答案为什么是这个了:
-
给父类 A 和子类 B 的 age 成员分配内存空间,由于 age 是 int 类型,所以默认值都是 0 ,内存变化图如下:
-
执行父类的成员变量声明和初始化块(顺序执行)
1 int age = 11;// 内存空间中父类的age值变为 22 2 { 3 System.out.print(age + " "); // 这时输出 11 4 age = 22; // 内存空间中父类的age值变为 22 5 System.out.print(1 + " ");// 输出 1 6 }执行完上面的语句之后内存最后的情况如下:
子类的age依然是 0
这时输出的值是:
11 1 -
执行父类 A 的构造函数(具体执行哪个构造函数是由子类的构造函数决定的)
1 public A() 2 { 3 System.out.print(2 + " ");// 会输出 2 4 printAge();// 因为这个函数在子类中被重写了,所以实际执行的是子类的那个方法,输出的是子类的 age 值,而此时子类 age 的值从刚才的内存中可以看出是:0 5 }这时输出的值是:
11 1 2 0 -
执行子类 B 的成员变量声明和初始化块(也是顺序执行)
1 int age = 3;// 子类的 age 变为 3 2 { 3 System.out.print(3 + " "); // 输出 3 4 }内存变化如下:
这时输出的值是:
11 1 2 0 3 -
执行子类 B 的构造函数
1 public B() 2 { 3 System.out.print(4 + " "); // 输出 4 4 printAge(); // 调用子类的方法,输出子类 B 的 age 值,这是 age 的值是 3,所以输出 3 5 }所以最后的结果是:
11 1 2 0 3 4 3
好了,现在时间点是 22:22,是时候洗澡去了,今天的培训笔记就先总结到这里吧!
不知道大家看完我总结的这篇笔记如何,我自己在听这个知识点的时候也是一脸的迷茫,怎么会这样的结果呢,最后一听内存变化的分析结果之后,就一切都明了啦;
所以看来自己还是不是很清楚对象的时候化顺序的,希望这个分析对大家有所收获。
总结的不好或者不对的地方,还请各位指出,学习是一个交流互动的过程,每个人看到的角度有时候确实挺大的,所以有时候会发现不一样的东西。
更多的JAVA学习总结,求关注我的每日笔记总结。bye!