자바 반사 메커니즘 개술 및 간단 한 실현

JAVA 반사 원 리 를 이해 하려 면 우 리 는 가상 컴퓨터 에 있 는 일부 지식 에 대해 간략하게 소개 해 야 한다.   1.1 가상 컴퓨터 가 Class 파일 을 불 러 오 는 과정:       JVM 류 로 딩 메커니즘 의 블 로그 에서 저 는 전체적인 절 차 를 소개 한 적 이 있 습 니 다. 여 기 는 로 딩 시 관련 부분 만 소개 합 니 다.       클래스 를 시작 하거나 다른 방식 으로 클래스 를 불 러 올 때 클래스 의 전체 제한 이름 을 통 해 이 클래스 의 바 이 너 리 흐름 을 가 져 온 다음 에 바이트 흐름 이 대표 하 는 정적 저장 구 조 를 방법 구역 의 운행 시 데이터 구조 로 전환 한 다음 에 이 클래스 를 대표 하 는 자바. lang. Class 대상 을 생 성하 여 방법 구역 과 같은 접근 입구 로 합 니 다.즉, 이 절 차 를 완성 하면 이 입 구 를 통 해 우 리 는 안에 저 장 된 데이터 구조 정 보 를 방문 할 수 있다.그리고 동적 로 딩 을 할 때 먼저 찾 습 니 다. 이 클래스 가 존재 하 는 지, 존재 하면 더 이상 로 딩 하지 않 고 한 부 를 유지 합 니 다.    class 파일 은 8 비트 바이트 를 기반 으로 하 는 바 이 너 리 스 트림 입 니 다. 각 데이터 항목 은 엄격 한 순서에 따라 Class 파일 에 치밀 하 게 배열 되 어 있 습 니 다. 그 안의 정 보 는 주로 다음 과 같은 정 보 를 설명 합 니 다.    1. 버 전 번호: 주 버 전과 차 버 전 번호    2. 상수 탱크: 글자 크기 (Literal) 와 기호 참조 (references) 를 저장 합 니 다.      2.1 글자 크기: 텍스트 문자열, final 형식의 상수 값 등      2.2 기호 참조:          a. 클래스 와 인터페이스의 모든 한정 이름          b. 필드 설명 과 설명자          c. 방법의 이름과 설명    3. 접근 표지:      a. 클래스 입 니까? 인터페이스 입 니까?      b. Public 등 유형 인지 여부      c. abstract 인지, final 등 표지 로 성명 되 었 는 지 여부    4. 클래스 인덱스, 부모 인덱스, 인터페이스 인덱스 집합      a. 클래스 인덱스: 이 클래스 의 전체 제한 이름 을 확인 합 니 다.      b. 부모 클래스 인덱스: 부모 클래스 의 전체 제한 이름 을 확인 합 니 다.      c. 인터페이스 색인 집합: 입구 로 서 계수기 로 서    5. 필드 테이블 집합:      정 보 는 필드 역할 영역 (Public, private 등 수정자), 인 스 턴 스 변수 인지 클래스 변수 (static), 가 변성 (final), 동시 다발 성 (volatile), 직렬 화 (transient) 등 정 보 를 포함한다.    6. 방법 집합:      접근 표지, 이름 색인, 설명자 색인, 속성 표 집합 을 포함 합 니 다.    7. 기타: 속성 표 집합, Code 속성 (명령) 등 을 포함 하여 여 기 는 잠시 소개 할 수 없 으 니 가상 컴퓨터 의 책 을 보 세 요.2. 반사 개념:    위의 간단 한 소 개 를 통 해 여러분 들 은 우리 의 Class 파일 이 JVM 에 불 러 온 후에 실제 저 장 된 정보 가 매우 많다 는 것 을 알 게 되 었 을 것 입 니 다. 그리고 위 에서 소개 한 것 은 모두 가 어느 정도 알 고 있 는 것 입 니 다. 예 를 들 어 방법, 속성 등 이 있 습 니 다. 그러면 반 사 는 무엇 입 니까?    반사 란 JAVA 언어 가 실 행 될 때 자체 심사 능력 을 가 질 수 있 도록 하 는 것 이다. 즉, JVM 은 코드 가 실 행 될 때 클래스 의 내부 정 보 를 얻 을 수 있 도록 허용 한다. 쉽게 말 하면 우 리 는 프로그램 이 실 행 될 때 방금 우리 가 소개 한 클래스 안의 정 보 를 얻 을 수 있다.    2.1 반사 에 자주 사용 되 는 방법:        a.forName(String className) :         주어진 문자열 이름 을 가 진 클래스 나 인터페이스 와 연 결 된 Class 대상 을 되 돌려 줍 니 다.        b.forName(String name, boolean initialize, ClassLoader loader) :         주어진 클래스 로 더 를 사용 하여 주어진 문자열 이름 을 가 진 클래스 나 인터페이스 와 연 결 된 Class 대상 을 되 돌려 줍 니 다.        c.getAnnotation(ClassannotationClass)         이 요소 의 지정 한 형식의 주석 이 존재 한다 면 이 주석 을 되 돌려 줍 니 다. 그렇지 않 으 면 null 로 돌아 갑 니 다.        d.getAnnotations()         이 요소 에 존재 하 는 모든 설명 을 되 돌려 줍 니 다.        e.getConstructor(Class... parameterTypes)         Constructor 대상 을 되 돌려 줍 니 다. 이 Class 대상 이 표시 하 는 클래스 의 지정 한 공공 구조 방법 을 반영 합 니 다.        f.getDeclaredField(String name)         Field 대상 을 되 돌려 줍 니 다. 이 대상 은 이 Class 대상 이 표시 하 는 클래스 나 인터페이스의 지정 한 성명 필드 를 반영 합 니 다.        g.getDeclaredMethod(String name, Class... parameterTypes)         Method 대상 을 되 돌려 줍 니 다. 이 대상 은 이 Class 대상 이 표시 하 는 클래스 나 인터페이스의 지정 한 성명 방법 을 반영 합 니 다.  public class Test { / / 구조 방법 public Test() { System. out. println ("매개 변수 구조 없 음"); } public Test(String str) { System. out. println ("참조 구조:" + str); } public void test(){ System. out. println ("일반 테스트 방법:"); } public static void staticTest(){ System. out. println ("정적 테스트 방법"); } / / 기본 속성 private Integer number; public String name = "장삼"; }  1. 클래스 로 딩:    public static void main(String[] args) throws Exception { Class<?> c = Class.forName("com.Test"); / / 여기에 클래스 를 불 러 옵 니 다. toString 방법, 인쇄 형식, getName 방법 을 조정 합 니 다. / / 클래스 가 이미 존재 하 는 것 을 동시에 발견 하면 로 딩 성공 을 설명 합 니 다. / / 여기 서 우 리 는 JDBC 연결 을 다시 얻 을 때 같은 종 류 를 동적 으로 불 러 오 는 데 자주 사용 합 니 다. / / 우 리 는 통 하지 않 는 업 체 의 연결 을 동적 으로 얻 을 수 있 습 니 다: Class. forName ("xxx. oracle / mysql") System. out. println ("클래스 정보:" + c); / / 동시에 이 로 더 를 직접 실행 할 수 있 습 니 다: Class. forName (name, initialize, loader) }  2 획득 방법 및 호출:    public static void main(String[] args) throws Exception { Class<?> c = Class.forName("com.Test"); / / 이것 은 지 정 된 방법 을 얻 는 것 입 니 다. 우 리 는 먼저 일반적인 방법 을 얻 습 니 다. Method m = c.getMethod("test"); / / 여기 서 실행 에 실 패 했 습 니 다. 우리 클래스 가 정례 화 되 지 않 았 기 때 문 입 니 다. // m.invoke(c); / / 그러면 안 됩 니 다. 기본 구 조 를 사 용 했 습 니 다. m.invoke(c.newInstance()); / / 그러나 정적 방법 은 예화 하지 않 으 면 된다. Method m2 = c.getMethod("staticTest"); m2.invoke(c); / / 물론 우 리 는 모든 방법 정 보 를 얻 을 수 있 습 니 다. / / 이 종류의 모든 방법 획득 c.getDeclaredMethods(); / / 계승 을 포함 한 모든 방법 획득 c.getMethods(); }  3. 필드 정보 획득:    public static void main(String[] args) throws Exception { Class<?> c = Class.forName("com.Test"); / / 개인 필드 는 공유 방식 으로 접근 할 수 없습니다. // Field f1 = c.getField("number"); / / public 필드 는 직접 접근 할 수 있 습 니 다. Field f = c.getField("name"); System.out.println(f); / / 이것 은 할당 입 니 다. 대상 인 스 턴 스 를 먼저 받 아야 합 니 다. 필드 에 값 을 부여 할 수 있 습 니 다. Object o = c.newInstance(); f.set(o, "2"); System.out.println(f.get(o)); / / 다른 방법 은 획득 method 와 차이 가 많 지 않 습 니 다. }  4. 기타 응용 프로그램:  반사 운용 이 매우 많다. 예 를 들 어 우리 가 잘 아 는 hibenate, spring, 그리고 다른 orm 프레임 워 크 는 모두 사용 해 야 한다.  // 이것 은 우리 가 모 의 한 실체 bean 이다. public class Bean { private Integer id; private String name; private String password; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }   // 이것 은 우리 가 모 의 한 실체 bean 이다. public class Bean { private Integer id; private String name; private String password; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }  소결:     1. 여기 서 반사 의 기본 적 인 운용 과 관련 원리 에 관 한 것들 을 소 개 했 는데 아직 깊이 들 어가 지 않 았 다.     2. 반 사 는 우리 에 게 매우 큰 유연성 을 주 었 으 나 동시에 많은 오 류 는 운행 기간 에 만 발견 할 수 있 으 니 사용 에 주의해 야 한다.     3. 반사 가 유연성 을 제공 하 는 동시에 성능 도 희생 했 습 니 다. JDK 1.6 + 버 전에 서 반사 되 는 일반 호출 은 직접 호출 보다 2 배 정도 느 립 니 다.       성능 이라는 부분 을 나중에 다시 연구 한 다음 에 최적화 방안 을 모집 하 다.  원문의 출처:http://qindongliang.iteye.com/blog/2023916  

좋은 웹페이지 즐겨찾기