-
자바 Inner static class 로딩 시점Java/자바를 더 깊게 2022. 4. 10. 01:23728x90
싱글톤 패턴을 공부하던 중 Lazy 로딩을 하며 스레드 세이프하게 구현하기 위해서 static inner class를 사용해서 구현했습니다.
Lazy Initialization, LazyHolder (static inner class를 사용하여 구현)
public class Singleton { private Singleton() {} private static class InnerInstanceClass { // 클래스 로딩 시점에서 생성 private static final Singleton uniqueInstance = new Singleton(); } public static Singleton getInstance() { return InnerInstanceClass.instance; } }
InnerInstanceClass는 싱글턴 클래스가 Load 될 때에도 Load 되지 않다가 getInstance()가 호출되었을 때 비로소 JVM 메모리에 로드되고, 인스턴스를 생성하게 됩니다.
여기서 저는 static 키워드를 사용하면 "JVM 메모리에 바로 로드되는 게 아녔던가?"라는 의문점을 갖게 되었고 더 조사를 하게 되었습니다.
실제로 언제 로드되는지 테스트
public class staticInnerClassTest { private staticInnerClassTest() { System.out.println("생성됨"); } private static class InnerInstanceClass { // 클래스 로딩 시점에서 생성 private static final staticInnerClassTest uniqueInstance = new staticInnerClassTest(); } public static staticInnerClassTest getInstance() { return InnerInstanceClass.uniqueInstance; } public static void main(String[] args) throws InterruptedException { System.out.println("Main start"); Thread.sleep(1000); staticInnerClassTest.getInstance(); } }
Main start가 출력되고 1초 뒤에 getInstance()가 호출될 때 "생성됨"이라는 메시지가 출력됩니다.
즉, 메서드가 호출될때 객체가 생성되는 것입니다.
핵심 키워드는 다음과 같습니다 JVM loading과 클래스 초기화를 잘 구분해야 합니다
JVM의 Class Loader는 Loading -> Linking -> Initialization 과정을 거칩니다.
저는 JVM이 클래스를 로드할 때 static으로 정의한 것이 모두 초기화되는 줄 알고 있었습니다.
하지만 이때 로딩이 되며 초기화가 동시에 이루어지는 것이 아녔습니다.
사실 조금만 생각해보면 언제 사용될지 모르는 모든 클래스들의 static 값을 모두 올리는 것은 비효율적으로 느껴집니다.
따라서 클래스가 시작할 때 초기화되면서 올라갑니다.
이제 다음 코드를 보면서 리마인드 하며 이해해보겠습니다.
public class Outer { private static final String TEST01 = "I'm TEST01"; static { System.out.println("1 - Initializing class Outer, where TEST01 = " + TEST01); } public static void main(String[] args) { System.out.println("2 - TEST01 --> " + TEST01 ); System.out.println("3 - Inner.class --> " + Inner.class); System.out.println("5 - Inner.info() --> " + Inner.info() ); } private static class Inner { static { System.out.println("4 - Initializing class Inner"); } public static String info() { return "I'm a method in Inner"; } } }
결과
1. 프로그램을 실행하면 'Outer' 클래스가 초기화됩니다.
static 변수 'TEST01'은 static 블록 전에 초기화됩니다.
현재까지는 아직 inner 클래스는 초기화되지 않았습니다.
2. Main 메서드가 호출되며 TEST01의 값을 출력합니다.
3. Inner.class를 출력해보면 초기화는 되지 않았지만 현재 로드된 상태임을 알 수 있습니다. (메모리 주소를 가지고 있음)
4. Inner.info()를 호출하기 위해서는 Inner 클래스를 초기화해야 합니다.
따라서 Inner 클래스가 초기화되며 static 구문이 출력됩니다.
5. 반환된 문자열이 출력됩니다.
출처
https://kdhyo98.tistory.com/70?category=971166
https://stackoverflow.com/questions/24538509/does-the-java-classloader-load-inner-classes
'Java > 자바를 더 깊게' 카테고리의 다른 글
JVM Warm-up 이란 (0) 2023.09.09 StringBuilder의 초기화 방법 (0) 2022.03.12 [Java] Java Multi-Thread Programming의 모든것을 알아보자 (0) 2022.03.02 [Java] Java Collection Framework의 모든것을 알아보자 (0) 2022.02.22 [Java] JVM이란? JVM(Java Virtual Machine)의 모든것을 알아보자 (2) 2022.02.17