一、非静态代码块
1、声明格式
【修饰符】 class 类名 {
{
非静态代码块
}
}
2、非静态代码块中的代码执行时机
(1)在"每次"创建对象的时候执行
(2)比构造方法早
Demo:
1 class MyClass{
2 private String str;
3
4 public MyClass(){
5 System.out.println("无参构造2");
6 }
7 public MyClass(String str){
8 this.str = str;
9 System.out.println("有参构造3");
10 }
11
12 {
13 System.out.println("非静态代码块1");
14 }
15 }
运行结果:先执行非静态代码中输出"非静态代码块1",然后执行无参构造方法输出"无参构造2"。
3、实例初始化过程
初始化过程:创建对象时,为对象进行初始化的操作
执行顺序:
① 为成员变量显示赋值
② 执行非静态代码块
③ 执行构造器
图解:
Java 编译器其实,会把这三个部分的代码,合成一个叫做 <init>(【形参列表】) 实例初始化方法。
即编译后的 .class 字节码文件中,是没有构造方法这个概念的。
<init>(【形参列表】) 实例初始化方法的代码就是由三个部分组成:
① 成员变量显示赋值的代码
② 非静态代码中的代码
③ 构造器中的代码
注意:
1、其中的 ① 和 ② 按顺序执行,而 ③ 一定是它们当中的最后执行的。
2、有几个构造器,就会有几个实例初始化方法。那么当创建对象的时候,调用对应的构造器时,其实执行的是对应的实例初始化方法 <init>(【...】)
二、继承中的非静态代码块
1、继承案例
先来看一个没有非静态的代码块的继承关系:
Demo:
1 public class TestInit {
2 public static void main(String[] args) {
3 Father f = new Father();
4 //执行父类的无参构造
5
6 Son s = new Son();
7 //先执行父类的无参构造,再执行子类的无参构造
8
9
10 Son s2 = new Son("HelloWorld");
11 //先执行父类的无参构造,再执行子类的有参构造1
12
13
14 Son s3 = new Son("Java", 10);
15 // 先执行父类的无参构造,再执行子类的有参构造1,然后再执行子类的有参构造2
16
17 }
18 }
19 //父类
20 class Father{
21 public Father(){
22 System.out.println("父类的无参构造");
23 }
24 }
25 // 子类
26 class Son extends Father{
27 private String str;
28 private int num;
29
30 public Son(){
31 //隐含了super(); 子类的构造器中一定会调用父类的构造器,默认调用父类的无参构造
32 System.out.println("子类的无参构造");
33 }
34
35 public Son(String str){
36 //隐含了super()
37 this.str = str;
38 System.out.println("子类的有参构造1");
39 }
40
41 public Son(String str,int num){
42 this(str); //这里有this就不会有super了,然后调用本类中的构造方法
43 this.num = num;
44 System.out.println("子类的有参构造2");
45 }
46 }
2、含有非静态代码块的继承关系
(1)先执行父类的实例初始化方法
它由三部分组成:
① 成员变量的显示赋值
② 非静态代码块
③ 构造方法
(2)再执行子类的实例初始化方法
它由三部分组成:
① 成员变量的显示赋值
② 非静态代码块
③ 构造方法
注意:
① super() 或 super(实参列表) 之前说的是调用父类的构造器,其实是调用父类对应的实例初始化方法
② super() 或 super(实参列表) 之前说的是在子类构造器的首行,其实是在子类实例初始化方法的首行,所以会先完成父类的初始化,再进行子类的初始化。
Demo:
1 public class TestInit {
2 public static void main(String[] args) {
3 Fu f = new Fu(); //312
4 System.out.println("==========");
5 Zi z = new Zi(); //312645
6 }
7 }
8
9
10 class Fu{
11 private String strFu = assignFu();
12 {
13 System.out.println("(1)父类的非静态代码块");
14 }
15 public Fu(){
16 System.out.println("(2)父类的无参构造");
17 }
18 public String assignFu(){
19 System.out.println("(3)父类的assignFu()");
20 return "fu";
21 }
22 }
23 class Zi extends Fu{
24 private String strZi = assignZi();
25 {
26 System.out.println("(4)子类的非静态代码块");
27 }
28 public Zi(){
29 //super() ==>调用父类的实例初始化方法,而且它在子类实例初始化方法的首行
30 System.out.println("(5)子类的无参构造");
31 }
32
33 public String assignZi(){
34 System.out.println("(6)子类的assignZi()");
35 return "zi";
36 }
37 }
运行结果:
图解:
3、含有非静态代码块的重写继承关系
Demo:
1 public class TestInit {
2 public static void main(String[] args) {
3 Ba b = new Ba(); // 312
4 System.out.println("============");
5 Er r = new Er(); //612645,因为子类重写了assign()
6
7 }
8 }
9 class Ba{
10 private String str = assign();
11 {
12 System.out.println("(1)父类的非静态代码块");
13 }
14 public Ba(){
15 System.out.println("(2)父类的无参构造");
16 }
17 public String assign(){
18 System.out.println("(3)父类的assign()");
19 return "ba";
20 }
21 }
22 class Er extends Ba{
23 private String str = assign();
24 {
25 System.out.println("(4)子类的非静态代码块");
26 }
27 public Er(){
28 //super() ==>调用父类的实例初始化方法,而且它在子类实例初始化方法的首行
29 System.out.println("(5)子类的无参构造");
30 }
31
32 public String assign(){
33 System.out.println("(6)子类的assign()");
34 return "er";
35 }
36 }
运行结果:
图解:
注意:this在构造器中,在实例化初始化方法中,代表的是正在创建的对象,当创建子类对象时,因为子类重写的 assign(),那么执行是子类重写的 assign() 方法。