首先说一下Java如何初始化。
对象的初始化工作必须在对象被调用之前完成。那么在创建对象时就需要调用类的初始化方法,而这个方法就是构造方法。为了确保构造方法名称唯一,即能够为Java编译器识别,在这里就是用于类名完全相同的方法作为构造方法。构造方法允许重载,但没有返回值。
下面就来看一下Java对象初始化的顺序。
在类内部,变量定义的先后顺序决定了初始化的顺序。即使变量定义散布于方法定义之间,他们仍然会在任何方法(包括构造方法)调用之前得到初始化。但是存在特殊的情况:静态变量。静态变量会在非静态变量初始前进行初始化,并且静态变量的初始化只有在必要时刻才会进行,且仅初始化一次。
最后看一下Java清理。
在java中有垃圾回收器负责回收无用对象占据的内存资源。但是,gc只能回收那些使用new关键字分贝的内存,对于其他方式的内存分配,gc无能为力。为了应对这种情况,java允许在类中定义finalize()方法。它的工作原理是这样的:一旦gc准备好释放对象的内存空间,将首先调用其finalize()方法,并且在下一次垃圾回收动作发生时,才真正回收对象占用的内存。但在实际应用中,不能依赖于finalize()完成清理工作,因为它只有在垃圾回收时才会被执行。那什么时候会执行gc呢?不一定了,也可能在程序结束时也没有执行。
那么实际上Java的初始化顺序可以分为以下三个方面:
1. Java的初始化顺序:(静态变量、静态初始化块)>(变量、初始化块)>构造器
来个例子:
public class InitialOrderTest {
private static String staticField = "静态变量";//静态变量
private String field = "变量"; // 变量
static { // 静态初始化块
System.out.println(staticField);
System.out.println("静态初始化块");
}
{// 初始化块
System.out.println(field);
System.out.println("初始化块");
}
InitialOrderTest() { // 构造器
System.out.println("构造器");
}
public static void main(String[] args) {
new InitialOrderTest();
}
}
输出:
静态变量
静态初始化块
变量
初始化块
构造器
2. 对于含有继承的情况会先初始化父类的,再初始化子类的
上例子:
class Parent {
// 静态变量
public static String p_StaticField = "父类--静态变量";
// 变量
public String p_Field = "父类--变量";
// 静态初始化块
static {
System.out.println(p_StaticField);
System.out.println("父类--静态初始化块");
}
// 初始化块
{
System.out.println(p_Field);
System.out.println("父类--初始化块");
}
// 构造器
public Parent() {
System.out.println("父类--构造器");
}
}
public class InitialOrderTest1 extends Parent {
// 静态变量
public static String s_StaticField = "子类--静态变量";
// 变量
public String s_Field = "子类--变量";
// 静态初始化块
static {
System.out.println(s_StaticField);
System.out.println("子类--静态初始化块");
}
// 初始化块
{
System.out.println(s_Field);
System.out.println("子类--初始化块");
}
// 构造器
public InitialOrderTest1() {
System.out.println("子类--构造器");
}
// 程序入口
public static void main(String[] args) {
new InitialOrderTest1();
}
}
输出:
父类--静态变量
父类--静态初始化块
子类--静态变量
子类--静态初始化块
父类--变量
父类--初始化块
父类--构造器
子类--变量
子类--初始化块
子类--构造器
注意:并不是父类完全初始化完毕后才进行子类的初始化,实际上子类的静态变量和静态初始化块的初始化是在父类的变量、初始化块和构造器初始化之前就完成了
3. 对于静态变量和静态初始化块之间 或者变量和初始化块之间的初始化顺序是取决于它们在类中出现的先后顺序。
无例无真相:
public class InitialOrderTest2 {
// 静态变量
public static TestA a = new TestA();
// 静态初始化块
static {
System.out.println("静态初始化块");
}
// 静态变量
public static TestB b = new TestB();
public static void main(String[] args) {
new InitialOrderTest2();
}
}
class TestA {
public TestA() {
System.out.println("Test--A");
}
}
class TestB {
public TestB() {
System.out.println("Test--B");
}
}
输出:
Test--A
静态初始化块
Test—B