一道关于Java变量初始化的面试题

首先来看笔者遇到的一道面试题,阅读下面的代码并给出执行结果:

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”

如果将Singletoncounter1counter2更改为动态变量,结果又是什么呢?

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/
请尊重作者的劳动成果,转载请注明出处!书影博客保留对文章的所有权利。

如果您喜欢这篇博文,欢迎您捐赠书影博客: ,查看支付宝二维码