자바에서 정적 제어 흐름(Static Control Flow)은 클래스가 JVM에 의해 로드되는 시점에 정적(static) 멤버들이 처리되는 순서를 의미합니다. 이 흐름은 정적 멤버를 식별하는 것으로 시작하여, 정적 블록을 실행한 뒤, 마지막으로 정적 main 메서드를 실행하는 순서로 진행됩니다.
정적 제어 흐름의 3단계
- 정적 멤버 식별: 소스 코드 위에서부터 아래로 정적 변수와 정적 블록을 식별하며, 이 단계에서 정적 변수에는 타입별 기본값(int의 경우 0)이 임시로 할당됩니다.
- 정적 변수 할당 및 정적 블록 실행: 코드에 작성된 순서대로 정적 변수에 실제 값이 대입되고 정적 블록이 차례로 실행됩니다.
- main 메서드 실행: 모든 정적 초기화가 끝난 후 비로소 정적 main 메서드가 실행됩니다.
예제 코드
public class Demo{
static int a = 97;
public static void main(String[] args){
print();
System.out.println("main 메서드 실행이 완료되었습니다");
}
static{
System.out.println(a);
print();
System.out.println("첫 번째 정적 블록 안입니다");
}
public static void print(){
System.out.println(b);
}
static{
System.out.println("두 번째 정적 블록 안입니다");
}
static int b = 899;
}
실행 결과
97 0 첫 번째 정적 블록 안입니다 두 번째 정적 블록 안입니다 899 main 메서드 실행이 완료되었습니다
출력 결과 분석
왜 이러한 순서로 출력되는지 단계별로 살펴보겠습니다.
1단계 – 정적 멤버 식별
JVM이 Demo 클래스를 로드하면 위에서부터 아래로 정적 멤버를 스캔합니다. 이 시점에는 변수 a와 b 모두 실제 값이 아니라 기본값 0을 가지고 있습니다.
2단계 – 정적 변수 할당과 정적 블록 실행
이후 코드에 작성된 텍스트 순서대로 처리가 진행됩니다.
- a에 97이 대입됩니다.
- 첫 번째 정적 블록이 실행되어 a의 값인 97을 출력합니다.
- 블록 안에서 print() 메서드가 호출되지만, 이 시점에는 b에 아직 899가 대입되기 전이므로 기본값인 0이 출력됩니다.
- “첫 번째 정적 블록 안입니다”라는 메시지가 출력됩니다.
- 두 번째 정적 블록이 실행되어 해당 메시지를 출력합니다.
- 마지막으로 b에 899가 대입됩니다.
3단계 – main 메서드 실행
모든 정적 초기화가 완료된 후 main 메서드가 실행됩니다. 여기서 호출된 print()는 이제 대입이 끝난 b의 값인 899를 출력하고, 이어서 완료 메시지가 출력됩니다.
코드 구조 요약
Demo 클래스에는 하나의 정적 변수(a)와 main 메서드가 있으며, main 메서드 내부에서 print() 함수를 호출합니다. 첫 번째 정적 블록은 앞서 정의된 정적 변수 a를 출력한 뒤 print() 함수를 다시 호출합니다. 별도로 정의된 정적 print() 함수는 또 다른 정적 변수 b를 출력하며, 두 번째 정적 블록은 안내 메시지를 출력합니다. 그리고 모든 정적 블록 바깥, 클래스의 맨 아래에 또 하나의 정적 정수 b가 선언되어 있습니다.
핵심 정리
- 정적 블록은 클래스가 로드될 때 딱 한 번만 실행됩니다.
- 정적 변수 할당과 정적 블록은 반드시 소스 코드에 작성된 순서대로 실행됩니다.
- 정적 블록에서 아직 값이 대입되지 않은 정적 변수를 참조하면 기본값이 출력됩니다.