자바의 static 블록
클래스 생성 시의 실행 블록, static 블록
클래스가 T메모리 영역 중 스태틱 영역에 배치될 때 실행되는 코드 블록이 있다. 바로 static 블록이다.
이전에 포스팅을 하였는지 기억이 가물가물하나, static 키워드가 붙은 정적 함수, 정적 메서드는 스태틱 영역에 할당된다. 이로 모든 메서드에서 접근할 수 있다.
예제 코드를 한 번 보겠다.
가장 큰 차이점은 이전 포스팅에서 객체 생성자 메서드로 선언했다면, 이번에는 static이라는 예약어 뒤에 바로 구현했다는 것이다.
해당 클래스의 객체 생성자 메서드로 인스턴스를 생성한 뒤 main 메서드에서 실행하면 [ 동물 클래스 ]가 Console 창에 출력됨을 확인할 수 있다. ( 편의상 main method 코드는 run 메서드에 작성하고 있습니다. )
그렇다면 main 메서드에서 Driver02을 실행하지 않고, [ main method ]만 출력하는 코드를 작성하면 어떻게 될까?
우리가 학습한 것은 static 메모리 영역에 선언된 것은 무조건 먼저 전처리가 된 뒤에 해당 코드들이 실행된다고 배웠을 것이다. 좀 더 정확하게 이야기하자면 main method에서 구현되거나 선언된 객체들이 전처리 된 뒤에 실행된다. 하지만 우리의 main method 코드에서는 Animal의 인스턴스를 생성하는 것은 그 어디에도 존재하지 않기에 단순히 [ main method ]만 출력한다.
객체 멤버인 인스턴스는 클래스가 static 영역에 자리한 뒤 객체 생성자를 통해 힙 영역에 생성된다. 위 코드는 클래스의 static 블록이 실행되고 있을 때 해당 클래스의 객체는 하나도 존재하지 않기 때문에 static 블록에서는 객체 멤버에 접근할 수 없는 것이다.
한 번 정리하겠다. 해당 패키지 또는 클래스가 처음 사용될 때 로딩되는 것이며, 모든 패키지와 모든 클래스가 프로그램이 시작하자마자 무조건 T 메모리 스태틱 영역에 로딩되는 것은 아니다.
즉, 위 코드처럼 작성되었을 때, Animal에 static 블럭으로 구현된 코드가 static 영역에 로딩된다.
결과는 아래와 같다.
위에 선언된 Animal 클래스의 static 블록이 실행된 뒤, main 메서드에서 다음 순서인 코드가 실행된다.
그렇다면 아래와 같은 경우는 출력 값이 어떻게 될까?
T메모리에 대한 개념이 없다면 아래와 같이 예상했을 것이다.
동물 클래스
animal 하나 생성했어요
동물 클래스
animal 두 개 생성했어요
main method
하지만 실제 결과는 아래 이미지와 같다.
앞서 언급되었던 static 영역을 잘 떠올리면 정답이 나온다. static 영역은 모든 곳에서 공통으로 접근할 수 있는 곳이다. 고로 중복적으로 생성된다기 보다는 하나가 생성되고 활용된다고 생각하면 쉽다. 그렇기에 아무리 Animal 인스턴스를 여러 개 생성하여도 static 블록은 단 한 번만 실행되는 것이다.
이번에는 클래스의 인스턴스를 만드는 것이 아닌 클래스의 정적 속성에 접근하는 예제를 살피겠다.
그러면 위와 같이 코드가 실행되며 로딩되고, 수행하는 것을 확인할 수 있다.
정리하겠다.
- 클래스 정보는 해당 클래스가 코드에서 맨 처음 사용되는 시점에 T 메모리 영역에 Static 영역으로 로딩되며,
이때 단 한 번 해당 클래스의 static 블록이 실행된다. - 클래스가 제일 처음 사용되는 경우는 아래 세 가지 경우 중 하나이다.
(1) 클래스의 정적 속성을 사용할 때
(2) 클래스의 정적 메서드를 사용할 때
(3) 클래스의 인스턴스를 최초로 만들 때
프로그램이 실행될 때 바로 클래스 정보가 T메모리의 static 영역에 로딩되지 않고, 클래스가 처음 사용될 때 로딩할까?
한 마디로 이야기하자면, 스태틱 영역도 메모리이기 때문이다. 메모리는 최대한 늦게 사용하고, 최대한 빨리 반환하는 것이 정석이다.
그 이유는 메모리 낭비를 막기 위해서라고 이해하면 좋다.
자바는 스태틱 영역에 한 번 올라가면 프로그램 종료 전까지 해당 메모리를 반환할 수 없다. 그렇지만 메모리 사용의 최적화를 위해 최대한 늦게 딱 필요한 타이밍에 메모리를 로딩한다고 보면 된다.
추가로 이야기하자면, static 블록과 유사하게 인스턴스 블록( instance block )도 존재한다. 아무런 표시없이 { } 블록을 사용하면 인턴스가 생성될 때마다 { } 블록이 실행되며, 이는 객체 생성자가 실행되기 전에 실행된다.