首先来看笔者遇到的一道面试题,阅读下面的代码并给出执行结果:
class Singleton {
private static Singleton singleton = new Singleton();
public static int counter1;
public static int counter2 = 0;
private Singleton() {
counter1++;
counter2++;
}
public static Singleton getInstance() {
return singleton;
}
}
public class TestSingleton {
public static void main(String[] args) {
Singleton s = Singleton.getInstance();
System.out.println(Singleton.counter1);
System.out.println(Singleton.counter2);
}
}
读完这段代码,笔者的第一个念头是由于counter1
没有赋初始值,所以会导致编译错(害羞),但面试官指出这段代码可以通过编译。
然后笔者又给出了答案“1 1”
,因为笔者觉得 public static int counter2;
与 public static int counter2 = 0;
是等价的。
但实际上程序的实际运行结果是“1 0”
,这是为什么呢?
Java中的变量根据作用域可划分为成员变量和局部变量两类。
1. 对于局部变量,未经初始化直接使用会导致编译错误(The local variable may not have been initialized),因此在使用局部变量之前必须对其显式地初始化。 2. 对于成员变量,Java会在声明时将其赋值为缺省值(基本数据类型为0,对象类型为null)。
而需要注意的是,Java对于成员变量的初始化,实际上是分解为两步执行的。
对于静态成员变量:
1. 根据静态成员变量在代码中的先后次序进行声明并赋值为缺省值 2. 在静态块内依次为变量进行赋值
对于动态成员变量:
1. 根据动态成员变量在代码中的先后次序进行声明并赋值为缺省值 2. 在动态块内依次为变量进行赋值
上面的Singleton
类的初始化过程实际上可以转化为:
class Singleton {
private static Singleton singleton;
public static int counter1;
public static int counter2;
static {
singleton = new Singleton();
counter2 = 0;
}
private Singleton() {
counter1++;
counter2++;
}
public static Singleton getInstance() {
return singleton;
}
}
执行过程如下:
首先将singleton, counter1, counter2分别赋值为null, 0, 0 然后执行静态块中的语句: 对创建的Singleton对象赋值给singleton变量,执行Singleton的构造方法,对counter1和counter2的值分别+1 然后将counter2赋值为0 因此最终结果是“1 0”
如果将Singleton
的counter1
和counter2
更改为动态变量,结果又是什么呢?
class Singleton {
private static Singleton singleton = new Singleton();
public int counter1;
public int counter2 = 0;
private Singleton() {
counter1++;
counter2++;
}
public static Singleton getInstance() {
return singleton;
}
}
public class TestSingleton {
public static void main(String[] args) {
Singleton s = Singleton.getInstance();
System.out.println(s.counter1);
System.out.println(s.counter2);
}
}
Singleton
类的代码可以转化为:
class Singleton {
private static Singleton singleton;
public int counter1;
public int counter2;
static {
singleton = new Singleton();
}
{
counter2 = 0;
}
private Singleton() {
counter1++;
counter2++;
}
public static Singleton getInstance() {
return singleton;
}
}
此时,Singleton
类初始化的顺序如下:
首先将singleton, counter1, counter2分别赋值为null, 0, 0 然后执行静态块中的语句: 对创建的Singleton对象赋值给singleton变量,首先执行动态块中的语句,将counter2赋值为0 然后执行Singleton的构造方法,对counter1和counter2的值分别+1 运行结果是“1 1”
本文链接:http://bookshadow.com/weblog/2016/02/28/java-variable-initialization-problem/
请尊重作者的劳动成果,转载请注明出处!书影博客保留对文章的所有权利。
郑州SEO优化 发布于 2016年2月29日 21:04 #
代码现在还没学会呢,继续加油