JavaOne 2007 Online Material

Tags:

Javaone online

JavaOne 2007의 pdf와 온라인 강의. 특히 Java Puzzler 놓치지 마시길.

그중에서도 이거 놓치지 마시길.

public class Elvis {
  // Recursive class initialization
  public static final Elvis ELVIS = new Elvis();
  
  private Elvis() { }

  private static final Boolean LIVING = true; // Too late

  private final Boolean alive = LIVING;
  public final Boolean lives() { return alive; }

  public static void main(String[] args) {
    System.out.println(ELVIS.lives() ? // Autounboxing!
        "Hound Dog" : "Heartbreak Hotel");
  }
}

출력 결과는? 수행단계는 다음과 같습니다.

1) main에서 ELVIS.lives() 호출하므로 ELVIS 클래스 초기화 시작.
2) 클래스 최초부분의 싱글턴 패턴에 따라 ELVIS에서 생성자 부름. ELVIS라는 클래스가 필요하므로 ELVIS를 초기화해야하는데 현재 초기화중이므로 별다른 할일은 없고 생성자 부름.
3) 생성자는 empty이지만 실제로는 내부적으로 인스턴스 변수(여기서는 alive)를 초기화함.
4) alive는 LIVING을 할당받는데 LIVING은 현재 null.
5) LIVING이 뒤늦게 초기화 된다고 해도 이미 alive에는 null들어갔음.
6) 결과는 Null Pointer Exception.

해결책은 LIVING의 초기화를 new ELVIS() 앞에 보내야 한다는 것입니다. 비슷한 예로 C++에서 멤버변수는 C++ 클래스 안에 선언된 변수의 순서에 따라 초기화됩니다.

class Foo {
  private:
    int i; // 초기화 가장 먼저
    int j; // 초기화 두번째
  public:
    Foo():j(7), i(0) { .. } // 여기서 j, i의 순서를 바꿔도 실제로는 i, j 순서로 초기화가 일어남
}

자바도 마찬가지로 인스턴스 변수와 static 변수가 혼재하면 변수의 선언순서에 따른다는 것.. 그러나 Boolean이 아니라 boolean으로 LIVING을 초기화 했다면 그 값은 실행시간에 ELVIS클래스가 초기화되는 것에 의존하지 않고 컴파일 시간에 값을 정하게되므로 위 프로그램에서 Boolean을 boolean으로 바꿀 경우 결과는 ELVIS.lives()는 true를 반환하게 됩니다.