Chap. 8 자바 가상 머신의 클래스 로더 사용 PS Lab. 이지연
목차 클래스의 로딩과 링킹 클래스 로더를 사용하지 않는 클래스 로딩 직접 만드는 클래스 로더 Class객체의 활용 리플렉션(Reflection)
클래스의 로딩 첫번째 단계 : 로딩 두번째 단계 : 링킹 클래스의 이름과 클래스 계층도 상에서의 클래스의 위치 및 그 클래스의 필드와 메소드의 종류에 대해 알게 됨 두번째 단계 : 링킹 클래스가 기본적인 형태를 제대로 갖추고 있는지 가상 머신의 제약조건을 거스르지 않음을 보장하도록 검증하는 단계 정적으로 초기화를 수행하는 <clinit>호출
로딩 모든 클래스 로더는 클래스 java.lang.ClassLoader의 서브 클래스 loadClass라고 부르는 메소드에 의해 로드 시작 Class loadClass(String name, boolean resolve); defineClass메소드 : 가상 머신에게 name에 해당하는 특정한 바이트 집합이 찾고자 하는 클래스라는 것을 알려주는 작업 수행
로딩(계속) 인터페이스는 링킹단계에서 검사 수퍼클래스를 로드하는 과정에서 클래스 로더가 찾을 수는 없지만 시스템자체에서 지원하는 클래스 class CoolWidget extends java.awt.Panel “java.awt.Panel”을 인자로 전달하여 findSystemClass호출
링킹 클래스가 몇 가지 요건을 충족시키는지 확인하기 위해 검증한 후 초기화 ClassLoader 내의 resolveClass메소드에 의해 수행 loadClass가 클래스를 리졸브(resolve)하도록 요청 받은 경우에,(resolve인자의 값이 true인 경우) loadClass의 마지막 부분에서 호출
링킹(계속) 검증(6장) 초기화 클래스의 <clinit>메소드를 호출 인터페이스에 의해 요구되는 메소드들은 모두 구현되어야 한다. 명령어들은 상수 풀의 참조자를 정확하게 사용해야 한다. 메소드에 의해 스택의 오버플로가 발생하면 안 된다. 메소드는 int를 reference로 사용하지 말아야 한다. 초기화 모든 정적필드를 위한 기억장소 할당 디폴트값 할당(숫자의 경우 0, reference의 경우 null) 클래스의 <clinit>메소드를 호출 필드 초기화 표현식과 메소드의 이름 없이 static으로 표시된 코드 처리
클래스 로더를 사용하지 않는 클래스 로딩 시스템 클래스 : 클래스 로더 없이 로드되는 클래스 CLASSPATH환경 변수를 사용하는 방법 ClassLoader클래스와 무관하게 클래스를 로드시키는 내부적 방법 name.class파일을 CLASSPATH내의 각 디렉토리에서 찾음 배열클래스는 클래스 로더를 사용하지 않고 로드된다.
직접 만드는 클래스 로더 ClassLoader의 서브클래스를 만들고 loadClass를 구현함으로써 새로운 클래스 로더를 만들 수 있다. 자바 1.0 플랫폼에서 클래스 로더를 작성하는 템플릿 : P.240, 241참고
클래스의 캐싱 defineClass가 호출되면 defineClass는 클래스의 이름을 반환된 Class 객체로 매핑 Class findLoadedeClass(String name); defineClass가 호출되면 defineClass는 클래스의 이름을 반환된 Class 객체로 매핑 이 후에 findLoadedClass는 어떤 클래스 로더에 의해서 로드되었느냐에 관계없이 동일한 이름에 대해 같은 Class객체 반환
예제 웹 브라우저의 자바 애플릿을 로드하기 위한 클래스 로더 : P. 243 참고 동적 컴파일과 함께 사용되는 ByteArrayClassLoader : P.244 참고
Class객체의 활용 newInstance : 새로운 인스턴스를 생성하여 디폴트 생성자를 호출시키고 인스턴스를 Object로서 반환 P. 245 예제 Object o=programOneClass.newInstance();
리플렉션 자바1.1 리플렉션 API : 클래스가 가지고 있는 메소드를 호출하거나 필드의 값을 읽고 쓸 수 있다. 필드나 메소드를 표현하기 위한 새로운 클래스들 필요 java.lang.reflect패키지 : 필드는 Field의 인스턴스, 메소드는 Method의 인스턴스로 표현 Field x=programOneClass.getField(“X”); Field y=programOneClass.getField(“Y”); x.setInt(o,90); y.setInt(o,20);
리플렉션(계속) 인자를 취하는 생성자를 호출하는 것 허용 Progam1 클래스에 Program1(int x, int y)생성자를 추가시켰다면 Class[] arg_types={Integer.TYPE, Integer.TYPE}; Constructor programOneConstructor= programOneClass.getConstructor(arg_type); Object[] arguments={new Integer(1000), new Integer(12)}; Object newProg1=programOneConstructor.newInstance(arguments);