构造函数,静态代码块,构造代码块执行顺序之案例究极大乱斗

静态代码块:用staitc声明,jvm加载类时执行,仅执行一次
构造代码块:类中直接用{}定义,每一次创建对象时执行。

构造函数

public HelloA(){//构造函数
    }

关于构造函数,以下几点要注意:
1.对象一建立,就会调用与之相应的构造函数,也就是说,不建立对象,构造函数时不会运行的。
2.构造函数的作用是用于给对象进行初始化。
3.一个对象建立,构造函数只运行一次,而一般方法可以被该对象调用多次。
构造代码块

{//构造代码块    
}

关于构造代码块,以下几点要注意:

构造代码块的作用是给对象进行初始化。
对象一建立就运行构造代码块了,而且优先于构造函数执行。这里要强调一下,有对象建立,才会运行构造代码块,类不能调用构造代码块的,而且构造代码块与构造函数的执行顺序是前者先于后者执行。
构造代码块与构造函数的区别是:构造代码块是给所有对象进行统一初始化,而构造函数是给对应的对象初始化,因为构造函数是可以多个的,运行哪个构造函数就会建立什么样的对象,但无论建立哪个对象,都会先执行相同的构造代码块。也就是说,构造代码块中定义的是不同对象共性的初始化内容。

静态代码块

static {//静态代码块 
}

关于静态代码块,要注意的是:

它是随着类的加载而执行,只执行一次,并优先于主函数。具体说,静态代码块是由类调用的。类调用时,先执行静态代码块,然后才执行主函数的。
静态代码块其实就是给类初始化的,而构造代码块是给对象初始化的。
静态代码块中的变量是局部变量,与普通函数中的局部变量性质没有区别。
java之static深入理解:https://blog.csdn.net/m0_37700275/article/details/88556697
一个类中可以有多个静态代码块

public class Test{
   static int cnt=6;
   static{
         cnt+=9;
   }
  public static void main(String[] args) {
         System.out.println(cnt);
  }
   static{
         cnt/=3;
   }
}

运行结果:
5

例子1:

public class HelloA {
    public HelloA(){//构造函数
        System.out.println("A的构造函数");   
    }
    {//构造代码块
        System.out.println("A的构造代码块");  
    }
    static {//静态代码块
        System.out.println("A的静态代码块");      
    }
    public static void main(String[] args) {
    }
}

运行结果:
A的静态代码块

例子2:

public class HelloA {
    public HelloA(){//构造函数
        System.out.println("A的构造函数");   
    }
    {//构造代码块
        System.out.println("A的构造代码块");  
    }
    static {//静态代码块
        System.out.println("A的静态代码块");      
    }
    public static void main(String[] args) {
        HelloA a=new HelloA();  
    }
}

运行结果:
A的静态代码块
A的构造代码块
A的构造函数

例子3:

public class HelloA {
    public HelloA(){//构造函数
        System.out.println("A的构造函数");   
    }
    {//构造代码块
        System.out.println("A的构造代码块");  
    }
    static {//静态代码块
        System.out.println("A的静态代码块");      
    }
    public static void main(String[] args) {
        HelloA a=new HelloA();
        HelloA b=new HelloA();
    }
}

运行结果:
A的静态代码块
A的构造代码块
A的构造函数
A的构造代码块
A的构造函数

对于一个类而言,按照如下顺序执行:

执行静态代码块
执行构造代码块
执行构造函数

例子4:

public class HelloA {
    public HelloA(){//构造函数
        System.out.println("A的构造函数");   
    }
    {//构造代码块
        System.out.println("A的构造代码块");  
    }
    static {//静态代码块
        System.out.println("A的静态代码块");      
    }
}
public class HelloB extends HelloA{
    public HelloB(){//构造函数
        System.out.println("B的构造函数");   
    }
    {//构造代码块
        System.out.println("B的构造代码块");  
    }
    static {//静态代码块
        System.out.println("B的静态代码块");      
    }
    public static void main(String[] args) {
        HelloB b=new HelloB();      
    }
}

运行结果:
A的静态代码块
B的静态代码块
A的构造代码块
A的构造函数
B的构造代码块
B的构造函数

当涉及到继承时,按照如下顺序执行:

执行父类的静态代码块,并初始化父类静态成员变量
执行子类的静态代码块,并初始化子类静态成员变量
执行父类的构造代码块,执行父类的构造函数,并初始化父类普通成员变量
执行子类的构造代码块, 执行子类的构造函数,并初始化子类普通成员变量

下面通过一个案例究极大乱斗来研究一下静态块,构造块 ,构造函数以及静态块调用构造对象的执行次序。
首先附上源代码:
Employee.java

package com.qcby.db;

import com.sun.org.apache.xalan.internal.xsltc.compiler.sym;

public class Employee {
	private String name = "lisi";
	{
		System.out.println("初始化1");
		name = "wangwu";
		age = 20;
	}
	private int age = 30;
	static {
		System.out.println("静态初始化1");
		System.out.println("id0:" + Employee.id);
		id = 40;
		System.out.println("id1:" + Employee.id);
		System.out.println("liuliu开始");
		Employee employee = new Employee("liuliu", 50);
		System.out.println(employee);
		System.out.println("liuliu id:" + employee.getId());
		System.out.println("liuliu结束");

}
private static int id = 30;

{
	System.out.println("初始化2");
	name = "zhaosi";
	age = 40;
}
static {
	System.out.println("id2:" + Employee.id);
	System.out.println("静态初始化2");
	id = 80;
	System.out.println("id3:" + Employee.id);

}

public static int getId() {
	return id;
}

public String getName() {
	return name;
}

public void setName(String name) {
	this.name = name;
}

public Employee(String name, int age) {
	super();
	System.out.println("有參構造器");
	this.name = name;
	this.age = age;
}

public Employee() {
	super();
	System.out.println("無參構造器");
	// TODO Auto-generated constructor stub
}

@Override
public String toString() {
	return "Employee [name=" + name + ", age=" + age + "]";
}
}

TestDefault.java

package com.qcby.servlet;

import com.qcby.db.Employee;

public class TestDefault {
	public static void main(String[] args) {
		System.out.println("tom开始");
		Employee tom = new Employee("tom", 20);
		System.out.println(tom);
		System.out.println(tom.getId());
		System.out.println("tom结束");
		System.out.println("jouty开始");
		Employee jouty = new Employee("jouty", 19);
		System.out.println(jouty);
		System.out.println(jouty.getId());
		System.out.println("jouty结束");
		System.out.println("jerry开始");
		Employee jerry = new Employee("jerry", 19);
		System.out.println(jerry);
		System.out.println(jerry.getId());
		System.out.println("jerry结束");

	}
}

运行TestDefault.java结果:
在这里插入图片描述
执行顺序:
1.执行语句System.out.println(“tom开始”);
输出 tom开始

2.执行语句Employee tom = new Employee(“tom”, 20);
2.1Employee类的加载,执行第一个static静态代码块;
2.2执行语句System.out.println(“静态初始化1”);
输出 静态初始化1
2.3执行语句System.out.println(“id0:” + Employee.id);
因为id还没有进行赋值,所以输出 id0:0
2.4执行语句id = 40;
2.5执行语句System.out.println(“id1:” + Employee.id);
因为id已经被赋值为40,所以输出 id1:40
2.6执行语句System.out.println(“liuliu开始”);
输出 liuliu开始

2.7执行语句Employee employee = new Employee(“liuliu”, 50);
因为类已经开始加载了,所以开始从开始执行,又因为第一个static静态代码块还没有执行完,所以先不执行其他静态代码块。又因为普通方法还没有被调用,所以先不执行。
2.7.1执行语句private String name = “lisi”;
2.7.2执行第一个构造代码块
2.7.2.1执行语句System.out.println(“初始化1”);
输出 初始化1
2.7.2.2执行语句name = “wangwu”;
2.7.2.3执行语句age = 20;
2.7.3private int age = 30;
2.7.4执行第二个构造代码
2.7.4.1执行语句System.out.println(“初始化2”);
输出 初始化2
2.7.4.2执行语句name = “zhaosi”;
2.7.4.3执行语句age = 40;
2.7.5执行构造方法 public Employee(String name, int age),因为传过来的参数是一个String,一个age。
2.7.5.1 执行语句super();
2.7.5.2执行语句System.out.println(“有參構造器”);
输出 有參構造器
2.7.5.3执行语句this.name = name;因为是this,所以哪个对象调用,就赋值哪个参数,那么被赋值为liuliu
2.7.5.4执行语句this.age = age;因为是this,所以哪个对象调用,就赋值哪个参数,那么被赋值为50
因为没有public Employee()相应的对象,所以不执行。
2.7.6执行public String toString()

2.8执行语句System.out.println(employee);
输出 Employee [name=liuliu, age=50]
2.9执行语句System.out.println(“liuliu id:” + employee.getId());

2.10执行public static int getId()
2.10.1执行语句return id;
输出 liuliu id:40

2.11执行System.out.println(“liuliu结束”);
输出 liuliu结束

2.12执行private static int id = 30;id被赋值为30

2.13执行第二个静态代码块
2.13.1执行System.out.println(“id2:” + Employee.id);
输出 id2:30
2.13.2执行System.out.println(“静态初始化2”);
输出 静态初始化2
2.13.3执行 id = 80;id被赋值为80
2.13.4执行System.out.println(“id3:” + Employee.id);
输出 id3:80

2.14执行语句private String name = “lisi”;
2.15执行第一个构造代码块
2.15.1执行语句System.out.println(“初始化1”);
输出 初始化1
2.15.2执行语句name = “wangwu”;
2.15.3执行语句age = 20;

2.16private int age = 30;

2.17执行第二个构造代码
2.17.1执行语句System.out.println(“初始化2”);
输出 初始化2
2.17.2执行语句name = “zhaosi”;
2.17.3执行语句age = 40;
2.18执行构造方法 public Employee(String name, int age),因为传过来的参数是一个String,一个age。
2.18.1 执行语句super();
2.18.2执行语句System.out.println(“有參構造器”);
输出 有參構造器
2.18.3执行语句this.name = name;因为是this,所以哪个对象调用,就赋值哪个参数,那么被赋值为tom
2.18.4执行语句this.age = age;因为是this,所以哪个对象调用,就赋值哪个参数,那么被赋值为20
因为没有public Employee()相应的对象,所以不执行。
2.19执行public String toString()

2.20执行语句System.out.println(tom);
输出 Employee [name=tom, age=20]
3.执行语句System.out.println(tom.getId());之前id被最终赋值为80,
所以输出 80
4.执行语句System.out.println(“tom结束”);
输出 tom结束
5.执行语句System.out.println(“jouty开始”);
输出 jouty开始

6.执行 Employee jouty = new Employee(“jouty”, 19);
6.1执行语句private String name = “lisi”;
6.2执行第一个构造代码块
6.2.1执行语句System.out.println(“初始化1”);
输出 初始化1
6.2.2执行语句name = “wangwu”;
6.2.3执行语句age = 20;

6.3private int age = 30;

6.4执行第二个构造代码
6.4.1执行语句System.out.println(“初始化2”);
输出 初始化2
6.4.2执行语句name = “zhaosi”;
6.4.3执行语句age = 40;

6.5执行构造方法 public Employee(String name, int age),因为传过来的参数是一个String,一个age。
6.5.1 执行语句super();
6.5.2执行语句System.out.println(“有參構造器”);
输出 有參構造器
6.5.3执行语句this.name = name;因为是this,所以哪个对象调用,就赋值哪个参数,那么被赋值为jouty
6.5.4执行语句this.age = age;因为是this,所以哪个对象调用,就赋值哪个参数,那么被赋值为19
因为没有public Employee()相应的对象,所以不执行。
6.6执行public String toString()

7.执行语句System.out.println(jouty);
输出 Employee [name=jouty, age=19]
8.执行语句System.out.println(jouty.getId());之前id被最终赋值为80,
所以输出 80
9.执行语句System.out.println(“jouty结束”);
输出 jouty结束
10.执行语句System.out.println(“jerry开始”);
输出 jerry开始

11.执行 Employee jerry = new Employee(“jerry”, 19);
11.1执行语句private String name = “lisi”;
11.2执行第一个构造代码块
11.2.1执行语句System.out.println(“初始化1”);
输出 初始化1
11.2.2执行语句name = “wangwu”;
11.2.3执行语句age = 20;

11.3private int age = 30;

11.4执行第二个构造代码
11.4.1执行语句System.out.println(“初始化2”);
输出 初始化2
11.4.2执行语句name = “zhaosi”;
11.4.3执行语句age = 40;

11.5执行构造方法 public Employee(String name, int age),因为传过来的参数是一个String,一个age。
11.5.1 执行语句super();
11.5.2执行语句System.out.println(“有參構造器”);
输出 有參構造器
11.5.3执行语句this.name = name;因为是this,所以哪个对象调用,就赋值哪个参数,那么被赋值为jerry
11.5.4执行语句this.age = age;因为是this,所以哪个对象调用,就赋值哪个参数,那么被赋值为19
因为没有public Employee()相应的对象,所以不执行。
11.6执行public String toString()

12.执行语句System.out.println(jerry);
输出 Employee [name=jerry, age=19]
13.执行语句System.out.println(jerry.getId());之前id被最终赋值为80,
所以输出 80
14.System.out.println(“jerry结束”);
输出 jerry结束

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值