자바 반사 메커니즘 과 동적 에이전트 (1)

11634 단어 CoreJava
앞에서 말 했 듯 이 자바 가 실 행 될 때 하나의 속성 방법 을 알 고 변경 할 수 있 습 니까?어떤 대상 에 대해 서도 그의 소속 류 를 알 고 그의 방법 을 호출 할 수 있 습 니까?답 은 긍정 적 이다.이러한 동적 인 정보 획득 및 동적 호출 방법의 메커니즘 은 자바 에서 '반사' (reflection) 라 고 부른다.
 
자바 반사 메커니즘 은 주로 다음 과 같은 기능 을 제공한다.
 
실행 할 때 임의의 대상 이 속 한 종 류 를 판단 합 니 다.운행 할 때 임의의 종류의 대상 을 구성한다.실행 할 때 임의의 클래스 가 가지 고 있 는 구성원 변수 와 방법 을 판단 합 니 다.실행 할 때 임의의 대상 을 호출 하 는 방법.
Reflection 은 자바 가 동적 (또는 준 동적) 언어 로 여 겨 지 는 관건 적 인 성질 이다.이 메커니즘 은 프로그램 이 실 행 될 때 Reflection API 를 통 해 알려 진 클 라 스 의 내부 정 보 를 얻 을 수 있 도록 합 니 다. 이 는 modifiers (예 를 들 어 Public, static 등), 슈퍼 클 라 스 (예 를 들 어 Object), 실 현 된 인터페이스 (예 를 들 어 Serializable) 를 포함 하고 fields 와 methods 의 모든 정 보 를 포함 하 며 실 행 될 때 fields 내용 을 바 꾸 거나 methods 를 호출 할 수 있 습 니 다.
 
일반적으로 개발 자 커 뮤 니 티 는 동적 언어 에 대해 대체적으로 인정 하 는 정 의 는 '프로그램 이 실 행 될 때 프로그램 구조 나 변수 유형 을 바 꿀 수 있 고 이런 언어 를 동적 언어 라 고 부른다' 는 것 이다.
 
JDK 에서 주로 다음 과 같은 종류 로 자바 반사 체 제 를 실현 합 니 다. 이런 종 류 는 모두 자바. lang. reflect 패키지 에 있 습 니 다. Class 류: 하나의 종 류 를 대표 합 니 다.Field 클래스: 대표 클래스 의 구성원 변수 (구성원 변수 도 클래스 의 속성 이 라 고 함);Method 류: 대표 적 인 방법;Constructor 류: 대표 적 인 구조 방법;Array 클래스: 동적 으로 배열 을 만 들 고 배열 에 접근 하 는 요 소 를 정적 으로 만 드 는 방법 을 제공 합 니 다.
 
예제 DateMethods Test 클래스 는 Reflection API 의 기본 적 인 역할 을 보 여 줍 니 다. 명령 행 매개 변수 가 지정 한 클래스 이름 을 읽 은 다음 에 이 클래스 가 가지 고 있 는 방법 정 보 를 인쇄 합 니 다. 코드 는 다음 과 같 습 니 다.
public class DateMethodsTest   
{   
    public static void main(String args[]) throws Exception   
    {   
        //                   
        Class> classType = Class.forName("java.util.Date");   
        //            
        Method methods[] = classType.getDeclaredMethods();   
        for (int i = 0; i < methods.length; i++)   
        {   
            System.out.println(methods[i].toString());   
        }   
    }   
}  

 
루틴 ReflectTester 클래스 는 Reflection API 의 기본 적 인 사용 방법 을 한층 더 보 여 주 었 다.ReflectTester 클래스 는 copy (Object object) 방법 이 있 습 니 다. 이 방법 은 매개 변수 object 와 같은 유형의 대상 을 만 든 다음 object 대상 의 모든 속성 을 새 대상 에 복사 하고 이 예 를 되 돌려 줍 니 다. 간단 한 자바 빈 만 복사 할 수 있 습 니 다. 자바 빈 의 모든 속성 이 Public 형식의 getXXX () 와 setXXX () 방법 이 있다 고 가정 하면 코드 는 다음 과 같 습 니 다.
public class ReflectTester {   
    public Object copy(Object object) throws Exception {   
        //           
        Class> classType = object.getClass();   
        System.out.println("Class:" + classType.getName());   
  
        //                    
        Object objectCopy = classType.getConstructor(new Class[] {}).newInstance(new Object[] {});   
  
        //             
        Field fields[] = classType.getDeclaredFields();   
  
        for (int i = 0; i < fields.length; i++) {   
            Field field = fields[i];   
  
            String fieldName = field.getName();   
            String firstLetter = fieldName.substring(0, 1).toUpperCase();   
            //         getXXX()        
            String getMethodName = "get" + firstLetter + fieldName.substring(1);   
            //         setXXX()        
            String setMethodName = "set" + firstLetter + fieldName.substring(1);   
  
            //         getXXX()     
            Method getMethod = classType.getMethod(getMethodName, new Class[] {});   
            //         setXXX()     
            Method setMethod = classType.getMethod(setMethodName, new Class[] { field.getType() });   
  
            //       getXXX()     
            Object value = getMethod.invoke(object, new Object[] {});   
            System.out.println(fieldName + ":" + value);   
            //        setXXX()     
            setMethod.invoke(objectCopy, new Object[] { value });   
        }   
        return objectCopy;   
    }   
  
    public static void main(String[] args) throws Exception {   
        Customer customer = new Customer("Tom", 21);   
        customer.setId(new Long(1));   
  
        Customer customerCopy = (Customer) new ReflectTester().copy(customer);   
        System.out.println("Copy information:" + customerCopy.getId() + " "  
                + customerCopy.getName() + " " + customerCopy.getAge());   
    }   
}   
  
class Customer {   
    private Long id;   
  
    private String name;   
  
    private int age;   
  
    public Customer() {   
    }   
  
    public Customer(String name, int age) {   
        this.name = name;   
        this.age = age;   
    }   
  
    public Long getId() {   
        return id;   
    }   
  
    public void setId(Long id) {   
        this.id = id;   
    }   
  
    public String getName() {   
        return name;   
    }   
  
    public void setName(String name) {   
        this.name = name;   
    }   
  
    public int getAge() {   
        return age;   
    }   
  
    public void setAge(int age) {   
        this.age = age;   
    }   
} 

 
ReflectTester 클래스 의 copy (Object object) 방법 은 다음 절 차 를 순서대로 수행 합 니 다.
(1) 대상 을 얻 는 유형: Class classType = object. getClass ();System.out.println("Class:"+classType.getName());
 
자바. lang. Object 클래스 에서 getClass () 방법 을 정 의 했 기 때문에 임의의 자바 대상 에 대해 서 는 이 방법 을 통 해 대상 의 유형 을 얻 을 수 있 습 니 다.Class 클래스 는 Reflection API 의 핵심 클래스 입 니 다. 다음 과 같은 방법 이 있 습 니 다. getName (): 클래스 의 전체 이름 을 얻 습 니 다.getFields (): 클래스 의 Public 형식의 속성 획득;getDeclared Fields (): 클래스 의 모든 속성 획득;getMethods (): 클래스 의 Public 형식 을 얻 는 방법;getDeclared Methods (): 클래스 를 얻 는 모든 방법;
 
getMethod (String name, Class [] parameterTypes): 클래스 의 특정한 방법, name 매개 변수 지정 방법의 이름, parameterTypes 매개 변수 지정 방법의 매개 변수 유형 을 얻 을 수 있 습 니 다.
getConstructors (): 클래스 의 Public 유형의 구조 방법 을 얻 습 니 다.getConstructor (Class [] parameterTypes): 클래스 의 특정 구조 방법 을 얻 고 parameterTypes 매개 변 수 는 구조 방법의 매개 변수 유형 을 지정 합 니 다.new Instance (): 클래스 의 매개 변수 가 없 는 구조 방법 으로 이러한 대상 을 만 듭 니 다.
 
(2) 기본 구조 방법 으로 새 대상 을 만 듭 니 다: Object objectCopy = classType. getConstructor (new Class [] {}). newInstance (new Object [] {});상기 코드 는 먼저 Class 류 의 getConstructor () 방법 을 호출 하여 Constructor 대상 을 얻 습 니 다. 이것 은 기본 적 인 구조 방법 을 대표 하고 Constructor 대상 의 new Instance () 방법 으로 인 스 턴 스 를 구성 합 니 다.
 
(3) 대상 의 모든 속성 획득: Field fields [] = classType. getDeclared Fields ();Class 류 의 getDeclared Fields () 방법 은 Public, proctected, 기본 값, private 접근 등급 의 속성 을 포함 하여 클래스 의 모든 속성 을 되 돌려 줍 니 다.
 
(4) 각 속성 에 해당 하 는 getXXX () 와 setXXX () 방법 을 얻 은 다음 에 이 방법 을 실행 하여 원래 대상 의 속성 을 새로운 대상 에 복사 합 니 다.
 
이상 은 반사 (reflection) 의 비교적 상세 한 해설 이다. 물론 진정한 공사 에 서 는 이렇게 번 거 롭 지 않 을 것 이다. 여 기 는 밑바닥 의 설명 이다.
 
 
다음 과 같은 종 류 는 반사 체 제 를 이용 하여 add () 와 echo () 방법 을 호출 하고 코드 는 다음 과 같다.
import java.lang.reflect.Method;   
  
public class InvokeTester {   
    public int add(int param1, int param2) {   
        return param1 + param2;   
    }   
  
    public String echo(String msg) {   
        return "echo: " + msg;   
    }   
  
    public static void main(String[] args) throws Exception {   
        Class> classType = InvokeTester.class;   
        Object invokeTester = classType.newInstance();   
  
        //   InvokeTester   add()     
        Method addMethod = classType.getMethod("add", new Class[] { int.class,   
                int.class });   
        Object result = addMethod.invoke(invokeTester, new Object[] {   
                new Integer(100), new Integer(200) });   
        System.out.println((Integer) result);   
  
        //   InvokeTester   echo()     
        Method echoMethod = classType.getMethod("echo",   
                new Class[] { String.class });   
        result = echoMethod.invoke(invokeTester, new Object[] { "Hello" });   
        System.out.println((String) result);   
    }   
}  

 
add () 방법의 두 매개 변 수 는 int 형식 입 니 다. add () 방법 을 나타 내 는 Method 대상 의 코드 는 다음 과 같 습 니 다. Method addMethod = classType. getMethod ("add", new Class [] {int. class, int. class});Method 류 의 invoke (Object obj, Object args []) 방법 으로 받 은 매개 변 수 는 대상 이 어야 하 며, 매개 변수 가 기본 형식 데이터 라면 해당 포장 유형의 대상 으로 변환 해 야 합 니 다.invoke () 방법의 반환 값 은 항상 대상 입 니 다. 실제 호출 된 방법의 반환 유형 이 기본 형식 데이터 라면 invoke () 방법 은 해당 하 는 포장 유형의 대상 으로 변환 하여 되 돌려 줍 니 다.
 
이 예 에서 InvokeTester 류 의 add () 방법의 두 가지 매개 변수 와 반환 값 은 모두 int 형식 임 에 도 불구 하고 add Method 대상 의 invoke () 방법 을 호출 할 때 Integer 형식의 매개 변수 만 전달 할 수 있 고 invoke () 방법의 반환 유형 도 Integer 유형 이 며 Integer 류 는 int 기본 유형의 포장 류 입 니 다.
Object result=addMethod.invoke(invokeTester,new Object[]{new Integer(100),new Integer(200)});System.out.println((Integer)result); //result 는 Integer 형식 입 니 다.
 
java. lang. Array 류 는 동적 으로 배열 요 소 를 만 들 고 방문 하 는 여러 가지 정적 방법 을 제공 합 니 다.다음 예 Array Tester 1. java 의 main () 방법 은 길이 가 10 인 문자열 배열 을 만 들 었 습 니 다. 이 어 색인 위치 가 5 인 요 소 를 "hello" 로 설정 한 다음 색인 위치 가 5 인 요소 의 값 을 읽 습 니 다. 코드 는 다음 과 같 습 니 다.
import java.lang.reflect.Array;   
  
public class ArrayTester1   
{   
    public static void main(String args[]) throws Exception   
    {   
        Class> classType = Class.forName("java.lang.String");   
        //        10         
        Object array = Array.newInstance(classType, 10);   
        //       5     "hello"   
        Array.set(array, 5, "hello");   
        //        5        
        String s = (String) Array.get(array, 5);   
        System.out.println(s);   
    }   
} 

 
자바 API 는 좋 은 도움말 자료 이 니 찾 아 보 세 요.예 를 들 어 상기 예: classType 은 String 형식의 대상 입 니 다.Array 클래스 의 new Instance (형식, 길이) 를 통 해 길이 가 10 인 String 인 Array 배열 을 만 들 었 습 니 다.Array 의 get 과 set 방법 을 통 해 5 (실제로는 Array 의 여섯 번 째 요소) 로 표 시 된 '배열 사각형' 에 문자열 'hello' 를 삽입 할 수 있 습 니 다.
 
다음 예 는 복잡 한 다 차원 배열 의 예 이지 만 1 차원 배열 만 알 면 다 차원 배열 을 이해 하기 어렵 지 않 을 것 이다.다 차원 배열 이란 하급 배열 이 하나의 '요소' 로 서 상급 배열 에 존재 할 뿐이다.
 
예 를 들 어 Array Tester 2 류 의 main () 방법 은 5 x 10 x 15 의 전체 배열 을 만 들 고 색인 위 치 를 [3] [5] [10] [10] 요소 의 값 을 37 로 설정 합 니 다. 코드 는 다음 과 같 습 니 다.
import java.lang.reflect.Array;   
  
public class ArrayTester2   
{   
    public static void main(String args[])   
    {   
        int[] dims = new int[] { 5, 10, 15 };   
        Object array = Array.newInstance(Integer.TYPE, dims);   
        Object arrayObj = Array.get(array, 3);   
        Class> cls = arrayObj.getClass().getComponentType();   
        System.out.println(cls);   
        arrayObj = Array.get(arrayObj, 5);   
        Array.setInt(arrayObj, 10, 37);   
        int arrayCast[][][] = (int[][][]) array;   
        System.out.println(arrayCast[3][5][10]);   
    }   
} 

 Class 는 Reflection 의 기원 입 니 다.탐색 하고 싶 은 class 에 대해 서 는 먼저 Class object 를 만들어 야 후자 가 수 십 여 개의 Reflection API 를 불 러 올 수 있 습 니 다.
 
자바 에 서 는 클래스 에 대응 하 는 클래스 object 를 여러 경로 로 생 성 할 수 있 습 니 다.
 
(1) getClass () 방법 활용:
String str = "abc";
Class class = str.getClass();
 
(2) Class. getSuperclass () 방법 활용:
Button b = new Button();
Class c1 = b.getSuperclass();
Class c2 = c1.getSuperclass();
 
(3) 정적 방법 Class. forName () 을 사용 합 니 다.
Class c1 = Class.forName("java.lang.String");
Class c2 = Class.forName("java.util.Date");
 
(4). class 문법 활용:
Class c1 = String.class;
Class c2 = java.awt.Button.class;
Class c3 = int.class;
Class C4 = int[].class;
 
(5) 원시 포장 류 의 TYPE 방법 활용:
Class c1 = Integer.TYPE;
Class c2 = Character.TYPE;
Class c3 = Boolean.TYPE;
Class c4 = Void.TYPE;
 
이 다섯 가지 방법 을 통 해 우리 가 원 하 는 대상 을 만 들 수 있다.
 [전환:http://phoenix-ghk.iteye.com/blog/392743]

좋은 웹페이지 즐겨찾기