Java 对象的初始化过程_上
- 2020 年 3 月 11 日
- 筆記
前言
本文主要以白话的形式 ‘简单’ 的描述在 java 中 new 对象的过程,之所以说是 ‘简单’ 的描述是因为,在本文中不会讲述底层的加载过程。
示例
首先认识几个知识点:
- 静态代码块 它会在类初始化的时候执行一次,仅能初始化类变量, 即被static修饰的成员变量,如果有多个静态代码块时,会按照静态代码块的编写顺序执行。实际上编译后多个静态代码块中的代码,会按编写时的顺序整合到一个静态代码块。
- 构造代码块 实际上源代码在被编译后,构造代码块中的代码就会被复制移动到构造方法代码的前面,也就会随着构造方法的运行而运行。如果存有多个构造方法时,将会在每个构造方法的代码之前都放置一遍 构造代码块中的代码 。所以也可以认为,构造代码块将在构造方法执行之前执行,如果存在有多个构造代码块时,那么就会按照构造代码块的编写顺序执行。由于构造代码块的代码是放到构造方法中执行的,所以作用也是初始化类实例变量。适用场景:
- 一个类,它不管创建多少个实例对象,都需要执行相同的初始化代码。
- 你的类有n个构造方法,而每个构造方法都需要执行相同的初始化代码。
- 构造方法 构造方法将会在类实例化时执行,也就是在被 new 时执行,需要注意的是,构造方法可以存在多个,如果你没有显示声明,一个没写的话,那编译器就会帮你加一个默认的构造方法。构造方法可以初始化类成员变量。
知道以上三个知识点后,那么就先创建一个Person类,观察一下
Person.java
package cn.ttext.test.init; public class Person { private String name; private int age; private String sex; static { System.out.println("静态代码块1"); } { System.out.println("构造代码块1"); } static { System.out.println("静态代码块2"); } { System.out.println("构造代码块2"); } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } }
对其编译,使用IDEA的反编译功能查看class文件内容
Person.class
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // package cn.ttext.test.init; public class Person { private String name; private int age; private String sex; public Person() { System.out.println("构造代码块1"); System.out.println("构造代码块2"); } public String getName() { return this.name; } public void setName(String name) { this.name = name; } public int getAge() { return this.age; } public void setAge(int age) { this.age = age; } public String getSex() { return this.sex; } public void setSex(String sex) { this.sex = sex; } static { System.out.println("静态代码块1"); System.out.println("静态代码块2"); } }
首先观察到,编译后的代码,和咱写的代码有点区别:
- 编译器自动帮我曾加了一个默认的,空参数的构造函数。
- 编译器删除了构造代码块,并将被删除的构造代码块中的代码,有序的放置到了构造方法中。
下面再在Person类中,显示声明多个构造函数。
Person.java
package cn.ttext.test.init; public class Person { private String name; private int age; private String sex; static { System.out.println("静态代码块1"); } { System.out.println("构造代码块1"); } public Person(String name) { this.name = name; } public Person(String name, int age) { this.name = name; this.age = age; } public Person(String name, int age, String sex) { this.name = name; this.age = age; this.sex = sex; } static { System.out.println("静态代码块2"); } { System.out.println("构造代码块2"); } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } }
查看编译后的内容
Person.class
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // package cn.ttext.test.init; public class Person { private String name; private int age; private String sex; public Person(String name) { System.out.println("构造代码块1"); System.out.println("构造代码块2"); this.name = name; } public Person(String name, int age) { System.out.println("构造代码块1"); System.out.println("构造代码块2"); this.name = name; this.age = age; } public Person(String name, int age, String sex) { System.out.println("构造代码块1"); System.out.println("构造代码块2"); this.name = name; this.age = age; this.sex = sex; } public String getName() { return this.name; } public void setName(String name) { this.name = name; } public int getAge() { return this.age; } public void setAge(int age) { this.age = age; } public String getSex() { return this.sex; } public void setSex(String sex) { this.sex = sex; } static { System.out.println("静态代码块1"); System.out.println("静态代码块2"); } }
看到编译后的结果说明几个问题:
- 显示声明构造函数后,编译器将不会帮我们创建默认的构造函数。
- 编译器删除了构造代码块,并将被删除的构造代码块中的代码,复制移动到每一个构造函数代码的最前面
- 编译器会将多个静态代码块中的代码,整合到一个静态代码块执行。
那现在看一下创建Person对象的控制台输出
Main.java
package cn.ttext.test.init; public class Main { public static void main(String[] args) { new Person("张三",18,"女"); System.out.println(); new Person("李四",18,"男"); } }
因为静态代码块只会随着类的加载而运行,所以第二次创建对象时,静态代码块没有运行。 结合上边的知识点看,是不是更明白了呢。
转发请注明本文链接。