클래스 로더가 .class 파일을 읽고 그 내용에 따라 적절한 바이너리 데이터를 만들고 “메소드” 영역에 저장.
이때 메소드 영역에 저장하는 데이터
FQCN(Fully Qualified Class Name)
클래스가 속한 패키지명을 모두 포함한 이름을 뜻한다.
클래스 | 인터페이스 | 이늄
메소드와 변수
로딩이 끝나면 해당 클래스 타입의 Class 객체를 생성하여 “힙" 영역에 저장.
package algorithm;
public class Hello {
public static void main(String[] args) {
/*
* .class 의 형태는 해당 클래스 타입의 Class 객체이다. Class<Hello>
*/
System.out.println(Hello.class);
//class algorithm.Hello
Hello hello = new Hello();
System.out.println(hello.getClass());
//class algorithm.Hello
}
}
링크
Verify, Prepare, Reolve(optional) 세 단계로 나눠져 있다.
검증(Verify): .class 파일 형식이 유효한지 체크한다.
Preparation: 클래스 변수(static 변수)와 기본값에 필요한 메모리
Resolve: 심볼릭 메모리 레퍼런스를 메소드 영역에 있는 실제 레퍼런스로 교체한다. Resolve는 Optional 이다.
초기화
Static 변수의 값을 할당한다. (static 블럭이 있다면 이때 실행된다.)
클래스 로더는 계층 구조로 이루어져 있으며 기본적으로 세가지 클래스 로더가 제공된다.
부트 스트랩 클래스 로더 - JAVA_HOME\lib에 있는 코어 자바 API를 제공한다. 최상위 우선순위를 가진 클래스 로더
플랫폼 클래스로더(Extension 클래스로더) - JAVA_HOME\lib\ext 폴더 또는ext.dirs 시스템 변수에 해당하는 위치에 있는 클래스를 읽는다.
애플리케이션 클래스로더 - 애플리케이션 클래스패스(애플리케이션 실행할 때 주는 -classpath 옵션 또는class.path 환경 변수의 값에 해당하는 위치)에서 클래스를 읽는다.
세 개의 클래스 로더(BootstrapClassLoader, PlatformClassLoader, AppClassLoader)가 기본적으로 생성되고 각각의 클래스 로더는 프로퍼티 값으로 설정된 위치의 클래스들만 읽어준다.
package me.devhistory;
public class App
{
Book book = new Book(); //심볼릭 메모리 레퍼런스
public static void main( String[] args )
{
ClassLoader classLoader = App.class.getClassLoader();
System.out.println(classLoader);
// AppClassLoader : 현재 App이라는 클래스를 읽은 클래스로더
System.out.println(classLoader.getParent());
// PlatformClassLoader : AppClassLoader의 부모 클래스로더
System.out.println(classLoader.getParent().getParent());
// BootstrapClassLoader : 네이티브 코드로 구현되어있어 null로 표시됨. PlatformClassLoader의 부모
}
}
※ 우리가 작성하는 코드들은 대부분 AppClassLoader가 읽는다.
클래스 로더 전체 동작 설명
클래스(.class)를 읽어달라고 하면 제일 최상위에 위치한 부트 스트랩 클래스로더에게 읽어달라고 부탁을 한다. 부트 스트랩 클래스로더는 설정된 프로퍼티 값을 기준으로 클래스를 찾게 되며 클래스를 발견하지 못 했다면 그 다음에 위치한 플랫폼 클래스로더에게 읽어달라고 부탁한다. 플랫폼 클래스로더도 클래스를 못 읽으면 애플리케이션 클래스로더가 직접 읽어 온다.
만약 애플리케이션 클래스로더도 못 읽는다면 ClassNotFoundexception 에러가 발생한다.
클래스를 읽어오는 로딩 과정을 완료하면 링크 과정을 수행한다.
우선 .class 파일 형식이 유효한지 체크한다.
그리고 기본적으로 필요한 메모리들을 준비한다.(Preparation)
마지막으로 심볼릭 레퍼런스를 메소드 영역에 있는 실제 레퍼런스로 교체한다. 이는 링크 과정에서 발생할 수도 있고 추후에 발생할 수도 있다.(Optional)
심볼릭 레퍼런스 : 기본 자료형(primitive data type)을 제외한 모든 타입(클래스와 인터페이스)이 해당하는데 참고하는 객체의 특정 메모리 주소를 참조 관계로 구성한 것이 아니라 참조하는 대상의 이름만 가지고 있는 것을 의미한다. 논리적인 레퍼런스라고 볼 수 있다.