자바 반사 메커니즘 분석

8987 단어 자바 딥 러 닝
최근 스프링 프레임 워 크 를 보고 있 는데 그 중 IOC 에서 가장 기본 적 인 기술 은 자바 의 반사 체 제 를 이용 하 는 것 이다.반사 메커니즘 은 일반적으로 제 시 된 클래스 이름(문자열 방식)에 따라 대상 을 동적 으로 생 성 하 는 것 이다.이런 프로 그래 밍 방식 은 대상 이 생 성 될 때 만 도대체 어떤 대상 인지 결정 할 수 있다.우 리 는 설정 파일 에 정 의 를 내리 기만 하면 된다.그 목적 은 유연성 과 유지 가능성 을 향상 시 키 는 것 이다.
밤 하나 부터 말하자면
package com.yixingu;

public class LiZi {
    private float price;
    private String variety;

    public float getPrice() {
        return price;
    }
    public void setPrice(float price) {
        this.price = price;
    }
    public String getVariety() {
        return variety;
    }
    public void setVariety(String variety) {
        this.variety = variety;
    }
    public LiZi(float price, String variety) {
        super();
        this.price = price;
        this.variety = variety;
    }

    public LiZi(){}

    public void produce(){
        System.out.println("variety: " + variety + " price: " + price);
    }

}

사용:
package com.yixingu;

public class Main {

    public static void main(String[] args) {
        /*
        //     
        LiZi lizi = new LiZi();
        lizi.setPrice(30);
        lizi.setVariety("   ");
        */

        //      
        LiZi lizi = new LiZi(30, "   ");
        lizi.produce();
    }

}

이 두 가지 방법 은 모두 전통 적 인 방식 으로 목표 류 를 직접 호출 하 는 방법 을 사용한다.다음 에 우 리 는 반사 체 제 를 통 해 간접 적 인 방식 으로 목표 류 를 조종 한다.
package com.yixingu;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Main {

    public static void main(String[] args) {
        /*
         * //      LiZi lizi = new LiZi(); lizi.setPrice(30);
         * lizi.setVariety("   ");
         */

        //       
        // LiZi lizi = new LiZi(30, "   ");

        //         LiZi   
        ClassLoader loader = Thread.currentThread().getContextClassLoader();
        try {
            Class clazz = loader.loadClass("com.yixingu.LiZi");
            //                     
            Constructor cons = clazz.getDeclaredConstructor((Class[]) null);
            LiZi lizi = (LiZi) cons.newInstance();
            //           
            Method setPrice = clazz.getMethod("setPrice", float.class);
            setPrice.invoke(lizi, 30);
            Method setVariety = clazz.getMethod("setVariety", String.class);
            setVariety.invoke(lizi, "   ");
            //    
            lizi.produce();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

이것 은 클래스 기능 을 직접 호출 하 는 효과 와 일치 하 는데 전 자 는 간접 적 으로 호출 되 고 후 자 는 직접 호출 된다.그 중에서 반사 에 주로 사용 되 는 것 은 클래스 로 더 ClassLoader 이다.
클래스 로 더
클래스 로 더 는 클래스 의 코드 파일 을 찾 아 JVM 내부 에서 대상 을 표시 하 는 구성 요 소 를 구성 하 는 것 입 니 다.자바 에 서 는 클래스 로 더 가 JVM 에 클래스 를 불 러 오 려 면 다음 절 차 를 거 쳐 야 합 니 다.1.불 러 오기:Class 파일 을 찾 고 가 져 옵 니 다.2.링크:검사,준비,해석 절 차 를 수행 하 는데 그 중에서 해석 절 차 는 선택 할 수 있 습 니 다.검사:class 파일 데 이 터 를 불 러 오 는 정확성 을 검사 합 니 다.준비:클래스 의 정적 변수 에 저장 공간 을 할당 합 니 다(기본 값 으로 초기 화 만).해석:기호 인용 을 직접 인용 으로 변환 합 니 다.3.초기 화:클래스 의 정적 변수,정적 코드 블록 에 대한 초기 화 작업(올 바른 값 으로 초기 화).
초기 화 된 장면
1)클래스 를 만 드 는 인 스 턴 스 2)특정한 유형의 정적 변 수 를 방문 하거나 이 정적 변 수 를 할당 합 니 다.(정적 컴 파일 에 접근 할 때 상수(즉,컴 파일 할 때 값 의 상수,컴 파일 할 때 상수 가 3 가지 조건 을 만족 시 켜 야 합 니 다.static 의,final 의,상수)클래스 초기 화 를 가 져 오지 않 습 니 다)3)호출 클래스 의 정적 방법 4)반사(Class.forName(xxx.xxx.xxx)5)클래스 의 하위 클래스 를 초기 화 합 니 다(부모 클래스 에 대한 주동 적 인 사용 에 해당 함).단,하위 클래스 를 통 해 부모 요 소 를 직접 참조 하여 하위 클래스 초기 화 를 일 으 키 지 않 습 니 다 6)자바 가상 머 신 은 시작 클래스 로 표시 되 어 있 습 니 다(main 방법 포함)
JVM 이 실 행 될 때 3 개의 ClassLoader:루트 로 더,ExtClassLoader(확장 클래스 로 더)와 APPLClassLoader(응용 클래스 로 더)를 다시 생 성 합 니 다.이 중 루트 로 더 는 classLoader 의 하위 클래스 가 아 닙 니 다.c+언어 로 작 성 된 것 이기 때문에 자바 에 서 는 볼 수 없습니다.루트 로 더 는 JRE 목표 의 rt.jar,charsets.jar 등 JRE 의 핵심 라 이브 러 리 를 불 러 옵 니 다.ExtClassLoader 와 APClassLoader 는 모두 classLoader 의 하위 클래스 입 니 다.그 중에서 ExtClassLoader 는 JRE 확장 디 렉 터 리 ext 의 JAR 클래스 패 키 지 를 담당 하고 APClassLoader 는 classpath 경로 의 클래스 패 키 지 를 불 러 옵 니 다.
이 세 개의 로 더 사이 에는 부자 계층 관계 가 존재 합 니 다.루트 로 더 는 ExtClassLoader 의 부모 로 더 이 고 ExtClassLoader 는 APPLClassLoader 의 부모 로 더 입 니 다.
밤 한 개:
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        System.out.println("current loader: " + classLoader);
        System.out.println("parent loader: " + classLoader.getParent());
        System.out.println("grandparent loader: " + classLoader.getParent().getParent());

JVM 에 클래스 를 불 러 올 때'전담 위탁 메커니즘'을 사용 합 니 다.'전체 책임"은 하나의 ClassLoader 가 클래스 를 불 러 올 때 다른 ClassLoader 를 표시 하지 않 고 사용 하지 않 는 한 이 클래스 가 의존 하고 인용 하 는 클래스 도 이 ClassLoader 에서 불 러 오 는 것 을 말 합 니 다."위탁 메커니즘'은 먼저 부모 적재 기 에 의뢰 하여 목표 클래스 를 찾 고 찾 을 수 없 는 상황 에서 만 자신의 클래스 경로 에서 목표 클래스 를 찾 아 불 러 오 는 것 을 말한다.이것 도 안전 을 고려 한 것 입 니 다.누군가가 악의 적 인 기본 클래스(java.lang.String)를 작성 하고 JVM 을 불 러 오 면 얼마나 무 서운 결 과 를 초래 할 지 생각해 보 세 요!그러나'전면 담당 위탁 메커니즘'이 있 기 때문에 java.lang.String 은 루트 로 더 에 의 해 영원히 불 러 옵 니 다.이렇게 하면 상기 안전 위험 의 발생 을 피 할 수 있 습 니 다.

좋은 웹페이지 즐겨찾기