常用的初始化方式
Java中可以使用括号进行初始化,并且分为静态代码块和非静态代码块。如下:
public class Test {
public static int num = 0;
String s = "";
{
s = "abc";
System.out.println("non static init");
}
static {
num = 1;
System.out.println("static init");
}
public void runTest(){
System.out.println(num);
System.out.println(s);
}
}
运行Test类的runTest方法,输出如下:
static init
non static init
1
abc
从输出结果可以看出,有static修饰的静态代码块在非静态代码块之前执行。
另外,非静态代码块与静态代码块有个区别:
静态代码块,在虚拟机加载类的时候就会加载执行,而且只执行一次;
非静态代码块,在创建对象的时候(即new一个对象的时候)执行,每次创建对象都会执行一次。
为了验证以上区别,写测试程序如下:
Test test1 = new Test();
Test1.runTest();
Test test2 = new Test();
test2.runTest();
输出结果如下:
static init
non static init
1
abc
non static init
1
abc
验证确实静态代码块只执行一次,非静态代码块每次创建都执行。
初始化的形式
除了以上的代码块方式进行初始化,Java中还有一种初始化方式,即双括号初始化。形式如下:
Test test = new Test(){
{
num = 2;
s = "aaa";
}
};
test.runTest();
这样输出结果为:
static init
non static init
2
aaa
这种初始化方式实际上是利用了匿名类的特性。外层的括号其实是创建了一个匿名的内部类,而内层的括号是匿名类的构造函数,所以可以直接插入初始化代码。
如果我们在内部构造函数和括号形式的构造函数中分别打印一条信息,可以得到如下结果:
static init
non static init
inner constructor
brackets constructor
2
aaa
括号中的代码晚于内部构造函数执行。
有什么利弊
尽管双括号初始化方式让编程的可读性变得简单,但是因为要创建一个匿名的内部类,匿名内部类会持有外部类的引用,有造成内存泄露的风险。