【Java】--반사(Java)

27821 단어 자바
【머리말】
                    ,       ,               。    ,               。             C,       ,                       。
   Brian Cantwell Smith 1982                        ,  meta-circular        3-Lisp       。

무엇
  :           (run time)     、                  。(    )

왜 반 사 를 사용 합 니까?
              Java                         。           ,                  。      ,          ,                  。

4.567917.확장 가능 한 특징 응용 프로그램 은 전체 한 정 된 이름 으로 확장 가능 한 대상 을 만 드 는 인 스 턴 스 를 통 해 외부 사용자 가 정의 하 는 클래스 를 사용 할 수 있 습 니 다
4.567917.클래스 브 라 우 저 와 시각 화 개발 환경 브 라 우 저 는 매 거 진 클래스 의 구성원 이 필요 합 니 다.시각 화 개발 환경 은 반 영 된 유형 정 보 를 이용 하여 개발 자 들 이 정확 한 코드 를 작성 하 는 데 도움 을 줄 수 있다
4.567917.디 버 거 와 테스트 도구 디 버 깅 자 는 수업 시간 에 개인 구성원 을 검사 할 수 있어 야 한다.테스트 빔 은 클래스 에 정 의 된 발견 가능 한 집합 API 를 반사 시스템 으로 호출 하여 테스트 세트 의 높 은 수준의 코드 를 덮어 쓸 수 있 도록 합 니 다
적용 장면 이 뭐 예요?
1).자바 의 반사 체 제 는 기본 구 조 를 만 들 때 매우 유용 하 다.한 마디 로 반사 체 제 는 많은 자바 구조의 초석 이다.일반적인 응용 차원 에 서 는 거의 사용 되 지 않 지만 이런 물건 은 현재 많은 오픈 소스 프레임 워 크 가 기본적으로 당신 에 게 포장 되 어 있 고 자신 은 거의 쓸 필요 가 없습니다.전형 적 인 것 은 hibenate 외 에 도 spring 도 많은 반사 체 제 를 사용한다.전형 적 인 것 은 xml 파일 이나 properties 에 설정 을 작성 한 다음 에 자바 류 에서 xml 또는 properties 안의 내용 을 분석 하고 문자열 을 얻 은 다음 에 반사 체 제 를 사용 하여 이 문자열 에 따라 특정한 클래스 의 Class 인 스 턴 스 를 얻 으 면 동적 으로 무언 가 를 배치 할 수 있 습 니 다.매번 코드 에서 new 나 다른 일 을 하지 않 아 도 됩 니 다.나중에 고 치 려 면 설정 파일 을 직접 고 쳐 야 합 니 다.코드 를 유지 하 는 것 이 편리 합 니 다.또한 가끔 은 특정한 수요 에 적응 해 야 합 니 다.자바 류 에서 반드시 다른 방법 을 직접 호출 할 수 있 는 것 이 아니 라 반사 체 제 를 통 해 이 루어 질 수 있 습 니 다.전체적으로 말 하면 자신 이 쓴 것 이 매우 적다.구체 적 으로 언제 그것 을 사용 해 야 하 는 지 는 수 요 를 봐 야 한다.반사 체 제 는 하나의 String 에 따라 당신 이 원 하 는 실체 대상 을 얻 은 다음 에 원래 의 것 을 호출 하 는 것 이다.하지만 스스로 틀 을 쓰 려 면 많이 쓴다.
2)소프트웨어 를 만 들 면 플러그 인의 기능 을 설치 할 수 있 습 니 다.플러그 인의 유형 이름 도 모 르 는데 이 대상 을 어떻게 예화 합 니까?프로그램 은 플러그 인(제3자)을 지원 하기 때문에 개발 할 때 몰 랐 습 니 다.그래서 코드 에서 New 를 나 올 수 없 지만 반사 할 수 있 습 니 다.반사,동적 로드 프로그램 집합 을 통 해 클래스 를 읽 고 표 시 를 검사 한 후에 대상 을 예화 하면 정확 한 인 스 턴 스 를 얻 을 수 있 습 니 다.
3)인 코딩 단계 에서 그 클래스 이름 을 모 릅 니 다.설정 파일 에서 클래스 이름 을 읽 으 려 면 new ClassName()을 하 드 인 코딩 할 방법 이 없습니다.반 사 를 사용 해 야 이 대상 을 만 들 수 있 습 니 다.반 사 는 알 수 없 는 응용 프로그램 을 확장 하기 위 한 것 입 니 다.예 를 들 어 프로그램 을 썼 습 니 다.이 프로그램 은 인 터 페 이 스 를 정 의 했 습 니 다.이 인터페이스의 dll 을 실현 하면 플러그 인 으로 이 프로그램 에 삽입 할 수 있 습 니 다.그럼 어떻게 이 루어 질 까요?반 사 를 통 해 이 루어 질 수 있다.dll 을 메모리 에 불 러 오고 반사 적 으로 dll 을 호출 하 는 방법 입 니 다.많은 공장 모델 이 바로 사용 하 는 반사 이다.
실례
반사 가 어떻게 일 하 는 지 알 고 싶 으 면 이 간단 한 예 를 고려 하 세 요.
  import java.lang.reflect.*;

   public class DumpMethods {
      public static void main(String args[])
      {
         try {
            Class c = Class.forName(args[0]);
            Method m[] = c.getDeclaredMethods();
            for (int i = 0; i < m.length; i++)
            System.out.println(m[i].toString());
         }
         catch (Throwable e) {
            System.err.println(e);
         }
      }
   }

호출:
 java DumpMethods java.util.Stack 

출력:
 public java.lang.Object java.util.Stack.push(
    java.lang.Object)
   public synchronized 
     java.lang.Object java.util.Stack.pop()
   public synchronized
      java.lang.Object java.util.Stack.peek()
   public boolean java.util.Stack.empty()
   public synchronized 
     int java.util.Stack.search(java.lang.Object)

즉,자바 util.stack 과 같은 방법 이름과 그들의 모든 한정 매개 변수 와 반환 유형 을 보 여 줍 니 다.
이 프로그램 은 class.forName 을 사용 하여 지정 한 클래스 를 불 러 오고 getDeclared Methods 를 사용 하여 클래스 에서 정의 하 는 방법 목록 을 검색 합 니 다.java.lang.reflect.Method 는 단일 한 방법 을 나타 내 는 클래스 입 니 다.
사용 반사 설정
반사 류,예 를 들 어 Method,java.lang.reflect 에서 찾 을 수 있 습 니 다.이런 종 류 를 사용 하려 면 반드시 세 가지 절 차 를 따라 야 한다.첫 번 째 단 계 는 작 동 할 클래스 를 위해 자바.lang.class 대상 을 가 져 오 는 것 입 니 다.java.lang.class 는 실행 중인 자바 프로그램의 클래스 와 인 터 페 이 스 를 표시 하 는 데 사 용 됩 니 다.
Class 대상 을 가 져 오 는 방법 은:
Class c = Class.forName("java.lang.String"); 

String 의 Class 대상 을 가 져 옵 니 다.다른 방법 은 다음 과 같다.
Class c = int.class; 
or
  Class c = Integer.TYPE; 

기본 형식의 클래스 정 보 를 가 져 옵 니 다.다음 방법 은 기본 유형의 포장 기의 미리 정 의 된 TYPE 필드(예 를 들 어 정수)에 접근 합 니 다.두 번 째 단 계 는 getDeclared Methods 등 방법 으로 이 성명 의 모든 방법 을 가 져 오 는 목록 입 니 다.
이 정 보 를 손 에 쥐 면 세 번 째 단 계 는 반사 API 를 사용 해 정 보 를 조작 하 는 것 이다.예 를 들 어 시퀀스:
 Class c = Class.forName("java.lang.String");
 Method m[] = c.getDeclaredMethods();      System.out.println(m[0].toString());

String 에서 설명 하 는 첫 번 째 방법의 텍스트 를 표시 합 니 다.다음 의 예 에서 세 가지 절 차 를 결합 시 켜 반 사 를 어떻게 사용 하여 구체 적 인 응용 을 해결 하 는 지 보 여 준다.
아 날로 그 연산 자의 인 스 턴 스
클 라 스 정보 가 손 에 있 으 면 보통 다음 단 계 는 클 라 스 대상 에 대한 기본 적 인 질문 이다.예 를 들 어 Class.isInstance 방법 은 instanceof 연산 자 를 모 의 하 는 데 사용 할 수 있 습 니 다.
  class A {}

   public class instance1 {
      public static void main(String args[])
      {
         try {
            Class cls = Class.forName("A");
            boolean b1 
              = cls.isInstance(new Integer(37));
            System.out.println(b1);
            boolean b2 = cls.isInstance(new A());
            System.out.println(b2);
         }
         catch (Throwable e) {
            System.err.println(e);
         }
      }
   }

이 예제 에서 A 에 사용 할 Class 대상 을 만 든 다음 클래스 인 스 턴 스 대상 을 검사 하여 A 의 인 스 턴 스 인지 확인 합 니 다.integer(37)는 아니 지만 new A()는.
한 가지 방법 을 찾아내다
반성 의 가장 가치 있 고 기본 적 인 사용 중 하 나 는 수업 시간 에 정 의 된 방법 을 찾 는 것 이다.이 를 위해 다음 코드 를 사용 할 수 있 습 니 다.
import java.lang.reflect.*;

   public class method1 {
      private int f1(
       Object p, int x) throws NullPointerException
      {
         if (p == null)
            throw new NullPointerException();
         return x;
      }

      public static void main(String args[])
      {
         try {
           Class cls = Class.forName("method1");

            Method methlist[] 
              = cls.getDeclaredMethods();
            for (int i = 0; i < methlist.length;
               i++) {  
               Method m = methlist[i];
               System.out.println("name 
                 = " + m.getName());
               System.out.println("decl class = " +
                              m.getDeclaringClass());
               Class pvec[] = m.getParameterTypes();
               for (int j = 0; j < pvec.length; j++)
                  System.out.println("
                   param #" + j + " " + pvec[j]);
               Class evec[] = m.getExceptionTypes();
               for (int j = 0; j < evec.length; j++)
                  System.out.println("exc #" + j 
                    + " " + evec[j]);
               System.out.println("return type = " +
                                  m.getReturnType());
               System.out.println("-----");
            }
         }
         catch (Throwable e) {
            System.err.println(e);
         }
      }
   }

프로그램 은 먼저 method 1 의 클래스 설명 을 가 져 온 다음 getDeclared Methods 를 호출 하여 Method 대상 목록 을 검색 합 니 다.클래스 에서 정의 하 는 모든 방법 입 니 다.Public,proctected,package,private 방법 을 포함 합 니 다.프로그램 에서 getDeclared Methods 가 아 닌 getMethods 를 사용 하면 계승 방법 에 대한 정 보 를 얻 을 수 있 습 니 다.Method 대상 의 목록 을 얻 으 면 매개 변수 유형,이상 유형,각 방법의 반환 유형 에 대한 정 보 를 표시 합 니 다.이러한 유형의 모든 종 류 는 기본 클래스 든 클래스 유형 이 든 모두 Class 설명자 에 의 해 표 시 됩 니 다.프로그램의 출력 은:
  name = f1
   decl class = class method1
   param #0 class java.lang.Object
   param #1 int
   exc #0 class java.lang.NullPointerException
   return type = int
   -----
   name = main
   decl class = class method1
   param #0 class [Ljava.lang.String;
   return type = void
   -----

구조 함수 에 대한 정 보 를 얻 는 유사 한 방법 은 클래스 의 구조 함 수 를 이해 하 는 데 사용 된다.예 를 들 면:

 import java.lang.reflect.*;

   public class constructor1 {
      public constructor1()
      {
      }

      protected constructor1(int i, double d)
      {
      }

      public static void main(String args[])
      {
         try {
           Class cls = Class.forName("constructor1");

           Constructor ctorlist[]
               = cls.getDeclaredConstructors();
         for (int i = 0; i < ctorlist.length; i++) {
               Constructor ct = ctorlist[i];
               System.out.println("name 
                 = " + ct.getName());
               System.out.println("decl class = " +
                            ct.getDeclaringClass());
               Class pvec[] = ct.getParameterTypes();
               for (int j = 0; j < pvec.length; j++)
                  System.out.println("param #" 
                     + j + " " + pvec[j]);
               Class evec[] = ct.getExceptionTypes();
               for (int j = 0; j < evec.length; j++)
                  System.out.println(
                    "exc #" + j + " " + evec[j]);
               System.out.println("-----");
            }
          }
          catch (Throwable e) {
             System.err.println(e);
          }
      }
   }

이 예제 에서 반환 형식의 정 보 를 검색 하지 못 했 습 니 다.구조 함수 가 실제 반환 형식 이 없 기 때 문 입 니 다.이 프로그램 을 실행 할 때 출력 은:
 name = constructor1
   decl class = class constructor1
   -----
   name = constructor1
   decl class = class constructor1
   param #0 int
   param #1 double
   -----

클래스 필드 찾기
클래스 에서 정 의 된 데이터 필드 도 찾 을 수 있다.이 를 위해 다음 코드 를 사용 할 수 있 습 니 다.
 import java.lang.reflect.*;

   public class field1 {
      private double d;
      public static final int i = 37;
      String s = "testing";

      public static void main(String args[])
      {
         try {
            Class cls = Class.forName("field1");

            Field fieldlist[] 
              = cls.getDeclaredFields();
            for (int i 
              = 0; i < fieldlist.length; i++) {
               Field fld = fieldlist[i];
               System.out.println("name
                  = " + fld.getName());
               System.out.println("decl class = " +
                           fld.getDeclaringClass());
               System.out.println("type
                  = " + fld.getType());
               int mod = fld.getModifiers();
               System.out.println("modifiers = " +
                          Modifier.toString(mod));
               System.out.println("-----");
            }
          }
          catch (Throwable e) {
             System.err.println(e);
          }
       }
   }

이 예 는 이전의 예 와 비슷 하 다.새로운 기능 은 Modifier 를 사용 하 는 것 입 니 다.이것 은 필드 구성원 에서 찾 은 수정자,예 를 들 어'private int'를 나타 내 는 반영 류 입 니 다.수정자 자 자 체 는 정수 로 표시 되 며,Modifier.toString 은'공식'성명 순서 로 문자열 표시 형식(예 를 들 어'final'이전의'static')을 되 돌려 줍 니 다.프로그램의 출력 은:
name = d
   decl class = class field1
   type = double
   modifiers = private
   -----
   name = i
   decl class = class field1
   type = int
   modifiers = public static final
   -----
   name = s
   decl class = class field1
   type = class java.lang.String
   modifiers =
   ----- 

방법 과 마찬가지 로 클래스(getDeclared Fields)에서 설명 한 필드 에 대한 정 보 를 얻 을 수 있 고,클래스(getFields)에서 정 의 된 필드 에 대한 정 보 를 얻 을 수 있 습 니 다.
이름 호출 방법
지금까지 제 공 된 예 는 모두 수업 정 보 를 얻 는 것 과 관련 이 있다.그러나 지 정 된 이름 을 호출 하 는 방법 과 같은 다른 방식 으로 반 사 를 사용 할 수도 있다.
어떻게 일 하 는 지 알 고 싶 으 면 다음 과 같은 예 를 고려 하 세 요.
 import java.lang.reflect.*;

   public class method2 {
      public int add(int a, int b)
      {
         return a + b;
      }

      public static void main(String args[])
      {
         try {
           Class cls = Class.forName("method2");
           Class partypes[] = new Class[2];
            partypes[0] = Integer.TYPE;
            partypes[1] = Integer.TYPE;
            Method meth = cls.getMethod(
              "add", partypes);
            method2 methobj = new method2();
            Object arglist[] = new Object[2];
            arglist[0] = new Integer(37);
            arglist[1] = new Integer(47);
            Object retobj 
              = meth.invoke(methobj, arglist);
            Integer retval = (Integer)retobj;
            System.out.println(retval.intValue());
         }
         catch (Throwable e) {
            System.err.println(e);
         }
      }
   }

프로그램 이 add 방법 을 호출 하려 고 한다 고 가정 하지만 실행 할 때 까지 알 수 있 습 니 다.즉,방법의 명칭 은 실행 기간 에 지정 된다(예 를 들 어 자바 빈 스 개발 환경 에서 완성 할 수 있다).위의 프로그램 은 이렇게 하 는 방법 을 보 여 주 었 다.getMethod 는 클래스 에서 두 개의 정수 매개 변수 유형 을 가지 고 적당 한 이름 을 가 진 방법 을 찾 는 데 사 용 됩 니 다.이 방법 이 발견 되 고 하나의 방법 대상 에 포착 되면 적당 한 유형의 대상 인 스 턴 스 를 호출 합 니 다.하나의 방법 을 호출 하려 면 매개 변수 목록 을 구성 해 야 합 니 다.그 중에서 전체 수치 37 과 47 은 정수 대상 에 포함 되 어 있 습 니 다.반환 값(84)도 정수 대상 에 싸 여 있다.
새 개체 만 들 기
구조 함 수 를 호출 하 는 것 은 새로운 대상 을 만 드 는 것 과 같 기 때문에 구조 함수 와 같은 방법 으로 호출 되 지 않 습 니 다.그래서 가장 가 까 운 예 는 다음 과 같다.
 import java.lang.reflect.*;

   public class constructor2 {
      public constructor2()
      {
      }

      public constructor2(int a, int b)
      {
         System.out.println(
           "a = " + a + " b = " + b);
      }

      public static void main(String args[])
      {
         try {
           Class cls = Class.forName("constructor2");
           Class partypes[] = new Class[2];
            partypes[0] = Integer.TYPE;
            partypes[1] = Integer.TYPE;
            Constructor ct 
              = cls.getConstructor(partypes);
            Object arglist[] = new Object[2];
            arglist[0] = new Integer(37);
            arglist[1] = new Integer(47);
            Object retobj = ct.newInstance(arglist);
         }
         catch (Throwable e) {
            System.err.println(e);
         }
      }
   } 

지정 한 매개 변수 형식 을 처리 하고 호출 하여 대상 의 새로운 인 스 턴 스 를 만 들 수 있 는 구조 함 수 를 찾 았 습 니 다.이 방법의 가 치 는 컴 파일 할 때 구조 함수 로 찾 고 호출 하 는 것 이 아니 라 순 전 히 동적 인 것 이다.필드 의 값 반 사 를 바 꾸 는 또 다른 용 도 는 대상 의 데이터 필드 의 값 을 바 꾸 는 것 이다.이 값 은 반 사 된 동적 특성 에서 다시 나 옵 니 다.그 중에서 실행 프로그램의 이름 을 통 해 필드 를 찾 은 다음 값 을 바 꿀 수 있 습 니 다.이것 은 다음 과 같은 예 시 를 통 해 설명 한다.
  import java.lang.reflect.*;

   public class field2 {
      public double d;

      public static void main(String args[])
      {
         try {
            Class cls = Class.forName("field2");
            Field fld = cls.getField("d");
            field2 f2obj = new field2();
            System.out.println("d = " + f2obj.d);
            fld.setDouble(f2obj, 12.34);
            System.out.println("d = " + f2obj.d);
         }
         catch (Throwable e) {
            System.err.println(e);
         }
      }
   } 

이 예제 에서 d 필드 의 값 은 12.34 로 설정 되 어 있 습 니 다.
배열 사용
반성 의 마지막 용 도 는 배열 을 만 들 고 조작 하 는 것 이다.자바 언어의 배열 은 전문 적 인 클래스 로 배열 인용 은 Object 에 할당 할 수 있 습 니 다.
배열 이 어떻게 작 동 하 는 지 알 고 싶 으 면 다음 과 같은 예 를 고려 하 십시오.
   import java.lang.reflect.*;

   public class array1 {
      public static void main(String args[])
      {
         try {
            Class cls = Class.forName(
              "java.lang.String");
            Object arr = Array.newInstance(cls, 10);
            Array.set(arr, 5, "this is a test");
            String s = (String)Array.get(arr, 5);
            System.out.println(s);
         }
         catch (Throwable e) {
            System.err.println(e);
         }
      }
   }

이 예제 에 서 는 10 개의 긴 문자열 배열 을 만 든 다음 배열 의 위치 5 를 문자열 값 으로 설정 합 니 다.이 값 을 검색 하고 표시 합 니 다.더 복잡 한 배열 작업 은 다음 코드 와 같 습 니 다.
  import java.lang.reflect.*;

   public class array2 {
      public static void main(String args[])
      {
         int dims[] = new int[]{5, 10, 15};
         Object arr 
           = Array.newInstance(Integer.TYPE, dims);

         Object arrobj = Array.get(arr, 3);
         Class cls = 
           arrobj.getClass().getComponentType();
         System.out.println(cls);
         arrobj = Array.get(arrobj, 5);
         Array.setInt(arrobj, 10, 37);

         int arrcast[][][] = (int[][][])arr;
         System.out.println(arrcast[3][5][10]);
      }
   }

이 예제 에 서 는 5 x 10 x 15 의 int 배열 을 만 든 다음 에 배열 의 위 치 를[3][5][10][10]값 37 로 설정 합 니 다.다 차원 배열 은 실제 배열 이기 때문에 예 를 들 어 첫 번 째 Array.get 이후 arrobj 의 결 과 는 10 x 15 의 배열 입 니 다.15 개의 긴 배열 을 얻 기 위해 서 이 배열 의 10 번 째 슬롯 은 Array.setInt 로 설정 되 어 있 습 니 다.생 성 된 배열 의 유형 은 동적 입 니 다.컴 파일 할 때 꼭 알 아야 할 것 은 아 닙 니 다.
총결산
자바 반 사 는 클래스 와 데이터 구조 에 대한 정 보 를 이름 동적 으로 검색 하고 실행 중인 자바 프로그램 에서 조작 할 수 있 도록 지원 하기 때문에 유용 합 니 다.이 기능 은 매우 강해 서 다른 일반적인 언어(예 를 들 어 C,C+,Fortran 또는 Pascal)에서 비슷 한 점 이 없다.

좋은 웹페이지 즐겨찾기