目录

裴先生
裴先生
发布于 2020-11-08 / 2 阅读
0
0

Java 构造器初始化详解

原创

本文基于《Thinking in Java》第五章 5.7 小节"构造器初始化"的内容整理而成,详细介绍了 Java 中对象初始化的顺序和机制。

初始化顺序

在类的内部,变量定义的先后顺序决定了初始化顺序,即使定义的位置在成员方法和构造器的后面,也会最先得到初始化。

示例代码:

/**
 * @author plm
 * @create 2021/2/17 18:18
 */
class House {
    private Window w1 = new Window(1);
 
    public House() {
        System.out.println("House : ()");
    }
 
    private Window w3 = new Window(3);
 
    void fun() {
        System.out.println("Have Fun.");
    }
 
    private Window w2 = new Window(2);
}
 
class Window {
    public Window(int num) {
        System.out.println("Window : (" + num + ")");
    }
}
 
public class OrderOfInitialization {
    public static void main(String[] args) {
        House house = new House();
        house.fun();
    }
}
 
/*
输出结果:
Window : (1)
Window : (3)
Window : (2)
House : ()
Have Fun.
*/

提示: 在日常开发过程中,我们不建议这么定义,不易维护与阅读。

静态数据的初始化

  • static 关键字不能应用于局部变量,因此它只能作用于域
  • 一个域是静态的基本类型域,并且没有进行初始化,那么它就会获得基本类型的标准初始值
  • 一个域是对象引用,那么它的默认初始值就是 null

示例代码:

/**
 * @author plm
 * @create 2021/2/17 18:39
 */
public class StaticInitialization {
    public static void main(String[] args) {
        System.out.println("Step1.");
        new Home();
        System.out.println("Step2.");
        new Home();
 
        father.fun_1(1);
 
        home.fun_2(2);
    }
 
    static Father father = new Father();
    static Home home = new Home();
}
 
class Child {
    public Child(int marker) {
        System.out.println("Child : (" + marker + ")");
    }
 
    void fun(int marker) {
        System.out.println("fun : (" + marker + ")");
    }
}
 
class Father {
    static Child c1 = new Child(1);
 
    public Father() {
        System.out.println("Father()");
        c1.fun(1);
    }
 
    void fun_1(int marker) {
        System.out.println("fun_1 : (" + marker + ")");
    }
 
    static Child c2 = new Child(2);
}
 
class Home {
    Child c3 = new Child(3);
 
    static Child c4 = new Child(4);
 
    public Home() {
        System.out.println("Home()");
        c4.fun(2);
    }
 
    void fun_2(int marker) {
        System.out.println("fun_2 : (" + marker + ")");
    }
 
    static Child c5 = new Child(5);
}
 
/*
输出结果:
Child : (1)
Child : (2)
Father()
fun : (1)
Child : (4)
Child : (5)
Child : (3)
Home()
fun : (2)
Step1.
Child : (3)
Home()
fun : (2)
Step2.
Child : (3)
Home()
fun : (2)
fun_1 : (1)
fun_2 : (2)
*/

如上代码得出:执行 main() 方法(静态方法),必须加载 StaticInitialization 类,然后其静态域 HomeFather 被初始化,对应的类就要被加载,由于它们也包含静态域 Child,所以 Child 也会被加载,这是一个特殊场景,所有的类都被 static 联系起来。

初始化的顺序:

  1. 静态对象(如果它们尚未因前面的对象创建而未被初始化的话)
  2. "非静态" 对象

提示:

  1. 构造器也是静态方法,即使它没有显示地使用 static 关键字:因此当首次创建类时,或者该类的静态方法及静态域首次被访问时,就会加载该类
  2. 静态初始化只会在该类加载时进行一次
  3. 为该类对象开辟内存空间
  4. 该类对象的所有基本类型设置为默认值,引用类型设置为 null
  5. 再进行程序员自己定义的初始化动作:比如给某个字段赋初始值 private String a = "123"
  6. 最后执行构造器

显示的静态初始化与非静态实例初始化

前者又称静态代码块,与其他静态初始化动作一样,只在类首次加载,或者首次访问该类的静态数据成员时,仅执行一次。

示例代码:

/**
 * @author plm
 * @create 2021/2/17 19:28
 */
public class ExplicitStatic {
    public static void main(String[] args) {
        System.out.println("Start.");
        new Cups();
 
        System.out.println("Step2.");
        new Cups();
    }
}
 
class Cups {
    static Cup c1;
    static Cup c2;
    Cup c3;
    Cup c4;
 
    static {
        c1 = new Cup(1);
        c2 = new Cup(2);
    }
 
    {
        c3 = new Cup(3);
        c4 = new Cup(4);
    }
 
    public Cups() {
         System.out.println("Cups init.");
    }
}
 
class Cup {
    Cup(int marker) {
        System.out.println("Cup : (" + marker + ")");
    }
 
    void fun(int marker) {
        System.out.println("Fun : (" + marker + ")");
    }
}
/*
输出结果:
Start.
Cup : (1)
Cup : (2)
Cup : (3)
Cup : (4)
Cups init.
Step2.
Cup : (3)
Cup : (4)
Cups init.
*/

如上,注意观察非静态实例初始化,仅仅缺少了 static 关键字,每次调用构造器,它总是会发生,并且总先于构造方法执行。

原创

版权声明:本博客原创文章,由 裴先生 2020年11月08日 发表。
转载说明:除特殊说明外本站文章皆由 CC BY-NC-SA 4.0 协议发布,转载须注明出处。


评论