静态代码块:用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结束