java 정적 필드 초기화(static initialization)

java의 정적필드는 클래스로더에 의해 메소드영역에 로드가 된다.정적 필드는 객체생성 이전 클래스가 메모리에 올라가는 시점부터 사용이 가능하다. 따라서 클래스의 생성자는 정적필드의 초기화 위치로 적합하지 못하다. 그렇다면 정적필드는 어떻게 초기화 해야 할까?

정적필드 초기화 1 : 선언과 동시에 초기화 하기

1
static double pi = 3.14;

일반적으로 정적필드는 위와 같이 선언과 동시에 초기화 한다. 하지만 외부환경의 영향이나 로직을 통해 정적필드를 초기화 하고 싶을 경우도 있을 것이다.

정적필드 초기화 2 : 정적영역(static block) 사용

1
2
3
4
5
static double pi;
static{
클래스명.pi = 3.14;
System.out.println("정적영역 초기화 완료...");
}

static { ... } 형태의 정적영역을 사용하여 정적필드를 초기화 할 수 있다. 정적영역 역시 클래스가 메모리에 로드되면서 동작한다.

정적영역 사용시 주의점 1 : 정적영역에서 인스턴스 멤버에 접근 할 수 없다.

정적영역은 클래스 단위의 영역이다. 모든 인스턴스는 자신의 클래스의 정적필드에 접근이 가능하지만, 그 반대로 정적영역에서 인스턴스의 필드에 접근 할 수 없다. 당연한 말일 것이다. 정적영역에서는 접근할 인스턴스를 구별할 수 없기 때문이다.

정적영역 사용시 주의점 2 : static final도 정적영역에서도 초기화 할 수 있다.

1
2
3
4
static final double PI;  //관용적으로 상수인경우 상수명을 대문자 사용
static {
클래스명.PI = 3.14;
}

**java에서 일반적인 인스턴스 단위의 final 필드을 초기화 하는 방법은 필드 선언과 동시 또는 생성자에서 초기화 해야 한다.**다른 방법은 존재하지 않는다. static final 필드는 final이전에 static영역, 즉 클래스 단위의 필드이기 때문에 일반적인 static 필드 처럼 선언시와 정적영역(static block)에서 초기화 할 수 있다.

정적영역 사용시 주의점 3 : interface의 상수는 정적영역에서 초기화 할 수 없다.

인터페이스의 멤버변수는 모두 상수(public static final)이다. 하지만 이 상수는 정적영역에서 초기화 할 수 없으며, 반드시 선언과 동시에 초기화 해야 한다. (20170917 추가)