Tuesday, March 1, 2016

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



http://bookshadow.com/weblog/2016/02/28/java-variable-initialization-problem/

首先来看笔者遇到的一道面试题,阅读下面的代码并给出执行结果:
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);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
读完这段代码,笔者的第一个念头是由于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;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
执行过程如下:
首先将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);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
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;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
此时,Singleton类初始化的顺序如下:
首先将singleton, counter1, counter2分别赋值为null, 0, 0

然后执行静态块中的语句:

  对创建的Singleton对象赋值给singleton变量,首先执行动态块中的语句,将counter2赋值为0
  
  然后执行Singleton的构造方法,对counter1和counter2的值分别+1

运行结果是“1 1”

Labels

Review (572) System Design (334) System Design - Review (198) Java (189) Coding (75) Interview-System Design (65) Interview (63) Book Notes (59) Coding - Review (59) to-do (45) Linux (43) Knowledge (39) Interview-Java (35) Knowledge - Review (32) Database (31) Design Patterns (31) Big Data (29) Product Architecture (28) MultiThread (27) Soft Skills (27) Concurrency (26) Cracking Code Interview (26) Miscs (25) Distributed (24) OOD Design (24) Google (23) Career (22) Interview - Review (21) Java - Code (21) Operating System (21) Interview Q&A (20) System Design - Practice (20) Tips (19) Algorithm (17) Company - Facebook (17) Security (17) How to Ace Interview (16) Brain Teaser (14) Linux - Shell (14) Redis (14) Testing (14) Tools (14) Code Quality (13) Search (13) Spark (13) Spring (13) Company - LinkedIn (12) How to (12) Interview-Database (12) Interview-Operating System (12) Solr (12) Architecture Principles (11) Resource (10) Amazon (9) Cache (9) Git (9) Interview - MultiThread (9) Scalability (9) Trouble Shooting (9) Web Dev (9) Architecture Model (8) Better Programmer (8) Cassandra (8) Company - Uber (8) Java67 (8) Math (8) OO Design principles (8) SOLID (8) Design (7) Interview Corner (7) JVM (7) Java Basics (7) Kafka (7) Mac (7) Machine Learning (7) NoSQL (7) C++ (6) Chrome (6) File System (6) Highscalability (6) How to Better (6) Network (6) Restful (6) CareerCup (5) Code Review (5) Hash (5) How to Interview (5) JDK Source Code (5) JavaScript (5) Leetcode (5) Must Known (5) Python (5)

Popular Posts