클래스 로더는 컴파일 된 자바의 클래스 파일 ( *.class ) 을 동적으로 로드하고,
JVM의 메모리 영역인 Runtime Data Areas에 배치하는 작업을 수행한다.
클래스 로더에서 class 파일을 로딩하는 순서는 다음과 같이 3단계로 구성된다
- Loading ( 로드 ) : 클래스 파일을 가져와서 JVM의 메모리에 로드한다.
- 클래스를 메모리에 올리는 Loading 기능은 한번에 메모리에 올리는게 아니라 애플리케이션에서 필요한 경우 동적으로 메모리에 적재한다.
- Linking ( 링크 ) : 클래스 파일을 사용하기 위해 검증하는 과정이다.
- Initialization ( 초기화 ) : 클래스 변수들을 적절한 값으로 초기화한다.\
JVM은 실행될때 모든 클래스를 메모리에 올려놓지 않고, 그때마다 필요한 클래스들을 메모리에 올려 관리한다.
클래스의 로드 시점
예제 코드
class Outer {
// static 변수
static String value = "> Outer 클래스의 static 필드 입니다.";
// static final 상수
static final String VALUE = "> Outer 클래스의 static final 필드 입니다.";
Outer() { System.out.println("> Outer 생성자 초기화"); }
// static 메서드
static void getInstance() {
System.out.println("> Outer 클래스의 static 메서드 호출");
}
// inner 클래스
class Inner {
Inner() { System.out.println("> Inner 생성자 초기화"); }
}
// static inner 클래스
static class Holder {
static String value = "> Holder 클래스의 static 필드 입니다.";
static final String VALUE = "> Holder 클래스의 static final 필드 입니다.";
Holder() { System.out.println("> Holder 생성자 초기화"); }
}
}
1. 아무것도 호출하지 않을 경우
public class Main {
public static void main(String[] args) {
}
}
- 메인 메소드가 위치하고 있는 Main 클래스만 로드
- static 멤버들이 있더라도 직접 가져와 사용하지 않으면 Outer 클래스는 로드되지 않는다
2. 인스턴스 생성
public class Main {
public static void main(String[] args) {
new Outer(); // 클래스의 인스턴스 생성
}
}
- 클래스를 인스턴스화 하면 당연히 클래스 ( Outer )가 로드된다.
- Outer 생성자 로드
- 그러나 내부 클래스는 직접 인스턴스를 생성하지 않으니 로드되지 않는다.
3.static 변수 호출
public class Main {
public static void main(String[] args) {
System.out.println(Outer.value); // 정적 변수 호출
}
}
- 클래스 내부의 static 멤버를 호출하면, 인스턴스화 하지 않아도 클래스( Outer ) 가 로드 된다.
- Outer의 static 필드 로드
4. static final 상수 호출
public class Main {
public static void main(String[] args) {
System.out.println(Outer.VALUE); // 정적 final 상수 호출
}
}
- static final 상수를 호출할 경우 static 변수와 다르게 Outer 클래스가 로드되지 않는다.
- java.lang.void ( static final 필드 ) 만 로드
- 왜냐하면 상수는 JVM의 Method Area의 Constant Pool ( 상수 풀 ) 에 따로 저장되어 관리 하기 때문.
5. static 메소드 호출
public class Main {
public static void main(String[] args) {
Outer.getInstance(); // static 메소드 호출
}
}
- static 변수호출과 같이 Outer 클래스가 로드
6. 내부 클래스 호출
public class Main {
public static void main(String[] args) {
new Outer().new Inner(); // 내부 클래스 인스턴스화
}
}
- 내부 클래스를 생성하기 위해서 외부 클래스를 먼저 생성하고 인스턴스화 해야하기 때문에 Outer 클래스와 Inner 클래스 둘다 로드
- 이러한 특징 때문에 내부 클래스를 static 으로 선언하지 않고 인스턴스 멤버 클래스로서 사용하면 메모리누수가 발생한다.
7.static 내부 클래스 호출
public class Main {
public static void main(String[] args) {
new Outer.Holder(); // static 내부 클래스 인스턴스화
}
}
- static inner 클래스는 외부 클래스럴 생성하지 않고 바로 직접 인스턴스화가 가능
- 일반 내부클래스와는 달리 외부 클래스를 로드하지 않는다는 차이점이 있다.
- static 이 붙었지만 static 멤버, static 메서드와 같이 생각하면 안된다.
static inner 클래스는 일반 클래스 inner클래스와 마찬가지로 외부 클래스를 생성해야 내부 클래스를 생성할 수 있다.
( 차이는 static은 외부 참조를 하지 않기 때문에 외부 클래스를 사용후 GC에의해 메모리 할당이 해제된다 )
- static 이 붙었지만 static 멤버, static 메서드와 같이 생각하면 안된다.
8. static 내부 클래스의 static 변수 호출
public class Main {
public static void main(String[] args) {
System.out.println(Outer.Holder.value);// static 내부 클래스 static 변수 호출
}
}
- 클래스를 인스턴스화 하지 않아도 static 멤버 변수를 호출하면 Holder 클래스가 로드된다.
- 그리고 외부 Outer 클래스는 로드되지 않는다.
- static 내부 클래스의 static final 상수를 호출하면 위에서 봤듯 Outer클래스와 그의 내부 클래스는 호출되지 않음.
( 상수는 Constant Pool 에서 관리하기 때문 )
- static 내부 클래스의 static final 상수를 호출하면 위에서 봤듯 Outer클래스와 그의 내부 클래스는 호출되지 않음.
'JAVA' 카테고리의 다른 글
JAVA - 리플렉션 ( Reflection ) (1) | 2024.04.12 |
---|---|
JAVA - Optional 사용하기 (0) | 2023.03.30 |
RestAPI 정리 (0) | 2023.03.06 |
빌더 패턴이란?? (0) | 2023.02.20 |
JAVA 9 - Collection Factory Method (0) | 2023.02.20 |