정적(static) 변수는 클래스가 로딩되는 시점, 즉 정적 블록이 실행되기 이전에 이미 생성됩니다. 정적 블록의 주된 목적은 바로 이 정적 변수에 값을 할당하는 것입니다.
정적 변수는 해당 클래스의 모든 인스턴스가 공유하는 값을 저장하며, 정적 블록은 클래스가 처음 로딩될 때 단 한 번 실행되는 코드 영역입니다. 따라서 클래스 로딩 시점에 반드시 수행되어야 하는 초기화 로직이 있다면, 그 로직을 정적 블록 안에 작성해야 클래스가 로딩될 때 자동으로 실행됩니다.
JVM이 클래스의 정적 멤버를 읽는 3단계
- 1단계: 위에서 아래 방향(top to bottom)으로 정적 멤버를 식별합니다.
- 2단계: 위에서 아래 방향으로 정적 변수 값 할당과 정적 블록을 실행합니다.
- 3단계: main 메서드를 실행합니다.
예제 코드
public class StaticFlow {
static int firstNumber = 10;
static {
firstMethod();
System.out.println("first static block");
}
public static void main(String[] args) {
firstMethod();
System.out.println("main method executed");
}
public static void firstMethod() {
System.out.println(secondNumber);
}
static {
System.out.println("second static block");
}
static int secondNumber = 20;
}실행 결과
0 first static block second static block 20 main method executed
실행 결과 분석
첫 번째 출력값이 20이 아니라 0으로 나오는 점이 의아할 수 있습니다. 그 이유는 JVM이 정적 멤버를 처리하는 방식 때문입니다.
- JVM은 먼저 클래스 전체를 훑으며
firstNumber,secondNumber등 모든 정적 멤버를 위에서부터 아래로 식별만 해둡니다. 이 시점에는 아직 값이 할당되지 않았습니다. - 이후 다시 위에서부터 아래로
firstNumber = 10을 할당하고, 첫 번째 정적 블록을 실행합니다. 이 블록 안에서 호출된firstMethod()는secondNumber를 출력하는데,secondNumber = 20은 아직 실행되지 않았으므로 int 타입의 기본값인 0이 출력됩니다. - 그다음 두 번째 정적 블록이 실행되고,
secondNumber = 20이 할당됩니다. - 마지막으로 main 메서드가 실행되면 이번에는
secondNumber에 20이 이미 할당된 상태이므로 20이 출력됩니다.
이처럼 정적 멤버의 식별과 실행(할당)이 서로 다른 단계에서 이루어진다는 점을 이해하면, 정적 블록과 정적 변수의 실행 순서를 정확히 예측할 수 있습니다.