자바 반사 학습 총화(5)

30949 단어 자바
반사 실례 대상 을 사용 하여 반사 메커니즘 을 사용 하면 우 리 는 운행 할 때 동적 으로 클래스 를 불 러 오고 대상 을 실례 화 할 수 있다.조작 대상 의 방법,클래스 구성원 의 값 을 바 꾸 고 심지어 개인(private)구성원 의 값 을 바 꿀 수 있다.
우 리 는 Class 의 new Instance()방법 으로 대상 을 실례 화 할 수 있 습 니 다.실례 화 된 대상 은 Object 로 전 달 됩 니 다.예 를 들 어:
Class c = Class.forName(className);
Object obj = c.newInstance();

다음 범례 동적 로드 list 인터페이스의 클래스:
package CoreJava.day_2;

import java.util.List;

/**
 * @author   
 * @date 2016/12/5
 */
public class NewInstanceDemo {
    public static void main(String[] args) {
        try {
            Class c = Class.forName(args[0]);
            List list = (List) c.newInstance();

            for (int i = 0; i < 5; i++) {
                list.add("element " + i);
            }

            for (Object o : list.toArray()) {
                System.out.println(o);
            }
        } catch (ClassNotFoundException e) {
            System.out.println("       ");
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}

출력:
java CoreJava.day_2.NewInstanceDemo java.util.ArrayList
element 0
element 1
element 2
element 3
element 4

실제로 동적 로 딩 클래스 에 반 사 를 사용 하려 면 대상 의 인터페이스 나 카 테 고리 에 대해 아무것도 모 르 고 위 에서 new Instance()로 전 송 된 대상 처럼 인터페이스 전환 을 할 수 없습니다.
로 딩 된 클래스 에 매개 변수 가 없 는 구조 방법 이 있 으 면 매개 변수 가 없 는 new Instance()로 초기 화 되 지 않 은 인용 을 구성 할 수 있 습 니 다.동적 로 딩 및 대상 생 성 시 대상 의 인용 을 지정 하려 면 매개 변수 유형 을 지정 하고 Constructor 대상 을 가 져 오 며 Constructor 의 new Instance()를 사용 하고 인 자 를 지정 해 야 합 니 다.
하나의 예 로 설명 할 수 있 습 니 다.먼저 student 클래스 를 정의 할 수 있 습 니 다.
package CoreJava.day_2;

/**
 * @author   
 * @date 2016/12/05
 */
public class Student {
    private String name;
    private int score;

    public Student() {
        name = "N/A";
    }

    public Student(String name, int score) {
        this.name = name;
        this.score = score;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setScore(int score) {
        this.score = score;
    }

    public String getName() {
        return name;
    }

    public int getScore() {
        return score;
    }

    public String toString() {
        return name + ":" + score;
    }
}

우 리 는 Class.forName()으로 Student 를 불 러 오고 두 번 째 매개 변수 가 있 는 구조 방법 으로 Student 인 스 턴 스 를 구성 할 수 있 습 니 다.
package CoreJava.day_2;

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

/**
 * @author   
 * @date 2016/12/5
 */
public class NewInstanceDemo2 {
    public static void main(String[] args) {
        try {
            Class c = Class.forName(args[0]);

            //     
            Class[] params = new Class[2];
            //     String
            params[0] = String.class;
            //     int
            params[1] = Integer.TYPE;

            //          
            Constructor constructor =
                    c.getConstructor(params);

            //       
            Object[] argObjs = new Object[2];
            argObjs[0] = "caterpillar";
            argObjs[1] = new Integer(90);

            //         
            Object obj = constructor.newInstance(argObjs);
            // toString()  
            System.out.println(obj);
        } catch (ClassNotFoundException e) {
            System.out.println("    ");
        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            System.out.println("        ");
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}

출력:
java NewInstanceDemo2 CoreJava.day_2.Student
caterpillar:90

호출 방법
반 사 를 사용 하면 클래스 의 대상 대 표를 되 찾 을 수 있 습 니 다.방법의 아 이 템 대 표 는 자바.lang.reflect.Method 의 인 스 턴 스 입 니 다.invoke()방법 으로 지정 한 방법 을 동적 으로 호출 할 수 있 습 니 다.예 를 들 어 위의 Student 의 setName()등 방법 을 호출 할 수 있 습 니 다.
package CoreJava.day_2;

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

/**
 * @author   
 * @date 2016/12/5
 */
public class InvokeMethodDemo {
    public static void main(String[] args) {
        try {
            Class c = Class.forName(args[0]);
            //             
            Object targetObj = c.newInstance();
            //       
            Class[] param1 = {String.class};
            //         
            Method setNameMethod = c.getMethod("setName", param1);
            //     
            Object[] argObjs1 = {"caterpillar"};
            //               
            setNameMethod.invoke(targetObj, argObjs1);


            Class[] param2 = {Integer.TYPE};
            Method setScoreMethod =
                    c.getMethod("setScore", param2);

            Object[] argObjs2 = {new Integer(90)};
            setScoreMethod.invoke(targetObj, argObjs2);
            //      
            System.out.println(targetObj);

        } catch (ClassNotFoundException e) {
            System.out.println("    ");
        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            System.out.println("      ");
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
    }
}

Student 클래스 를 불 러 오고 인 스 턴 스 를 생 성 할 수 있 습 니 다.이 어 setName()과 setScore()방법 을 동적 으로 호출 할 수 있 습 니 다.setName()과 setScore()를 호출 하 는 매개 변 수 는"caterpillar"와 90 이기 때 문 입 니 다.
아주 적은 상황 에서 우 리 는 자바 의 액세스 제한 을 돌파 하여 보 호 받 는(proctected)또는 개인(private)방법 을 호출 해 야 합 니 다.(예 를 들 어 우 리 는 하나의 구성 요소(Component)를 받 았 지만,우 리 는 그것 의 원본 코드 를 수정 하여 특정한 개인 방법의 권한 을 바 꿀 수 없습니다.우 리 는 반드시 특정한 개인 방법 을 호출 해 야 합 니 다)이때 우 리 는 반사 메커니즘 을 사용 하여 목적 을 달성 할 수 있다.액세스 사유 방법의 예 는 다음 과 같다.
Method privateMethod = 
            c.getDeclaredMethod("somePrivateMethod", new Class[0]);
privateMethod.setAccessible(true);
privateMethod.invoke(targetObj, argObjs);

반사 적 으로 동적 호출 방법 을 사용 하 는 실례 중 하 나 는 JavaBean 의 설정 이다.예 를 들 어 JSP/servlet 에 서 는 사용자 의 요청 이름과 JavaBean 의 속성 에 따라 자동 으로 대비 하여 요청 값 을 지정 한 JavaBean 에 설정 하고 매개 변수 유형 에 따라 자동 으로 변환 할 수 있다.
다음은 맵 의 작은 예 입 니 다.
package CoreJava.day_2;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Map;

/**
 * @author   
 * @date 2016/12/5
 */
public class CommandUtil {
    public static Object getCommand(Map requestMap,
                                    String commandClass)
            throws Exception {
        Class c = Class.forName(commandClass);
        Object o = c.newInstance();

        return updateCommand(requestMap, o);
    }

    //   reflection          
    public static Object updateCommand(
            Map requestMap,
            Object command)
            throws Exception {
        Method[] methods =
                command.getClass().getDeclaredMethods();

        for (int i = 0; i < methods.length; i++) {
            //   private、protected  
            //       set     
            if (!Modifier.isPrivate(methods[i].getModifiers()) &&
                    !Modifier.isProtected(methods[i].getModifiers()) &&
                    methods[i].getName().startsWith("set")) {
                //      set  
                String name = methods[i].getName()
                        .substring(3)
                        .toLowerCase();
                //   setter       
                //      setter   
                if (requestMap.containsKey(name)) {
                    String param = (String) requestMap.get(name);
                    Object[] values = findOutParamValues(
                            param, methods[i]);
                    methods[i].invoke(command, values);
                }
            }
        }
        return command;
    }

    //       
    private static Object[] findOutParamValues(
            String param, Method method) {
        Class[] params = method.getParameterTypes();
        Object[] objs = new Object[params.length];

        for (int i = 0; i < params.length; i++) {
            if (params[i] == String.class) {
                objs[i] = param;
            } else if (params[i] == Short.TYPE) {
                short number = Short.parseShort(param);
                objs[i] = new Short(number);
            } else if (params[i] == Integer.TYPE) {
                int number = Integer.parseInt(param);
                objs[i] = new Integer(number);
            } else if (params[i] == Long.TYPE) {
                long number = Long.parseLong(param);
                objs[i] = new Long(number);
            } else if (params[i] == Float.TYPE) {
                float number = Float.parseFloat(param);
                objs[i] = new Float(number);
            } else if (params[i] == Double.TYPE) {
                double number = Double.parseDouble(param);
                objs[i] = new Double(number);
            } else if (params[i] == Boolean.TYPE) {
                boolean bool = Boolean.parseBoolean(param);
                objs[i] = new Boolean(bool);
            }
        }
        return objs;
    }
     public static void main(String[] args) throws Exception {
        Map request = 
                  new HashMap();
        request.put("name", "caterpillar");
        request.put("score", "90");
        Object obj = CommandUtil.getCommand(request, args[0]);
        System.out.println(obj);
    }
}

CommandUtil 은 방법 상의 매개 변수 유형 에 따라 맵 의 value 를 해당 하 는 형식 으로 자동 으로 변환 할 수 있 으 며,현재 기본 형식 과 String 을 변환 할 수 있 습 니 다.
출력:
java CommandUtilDemo CoreJava.day_2.Student
caterpillar:90

물론 구성원 변 수 를 수정 할 수 있 습 니 다.클래스 의 구성원 속성(Field)을 직접 읽 는 것 은 격려 되 지 않 지만 우 리 는 공공(Public)구성원 속성 을 직접 액세스 할 수 있 습 니 다.우 리 는 심지어 반사 체 제 를 통 해 개인 적 인 구성원 변 수 를 읽 을 수 있 습 니 다.예 를 들 어 설명 할 수 있 습 니 다.
package CoreJava.day_2;

/**
 * @author   
 * @date 2016/12/5
 */
public class TestField {
    public int testInt;
    public String testString;

    public String toString() {
        return testInt + ":" + testString;
    }
}

그리고 반사 메커니즘 을 이용 하여 구성원 변 수 를 동적 으로 읽 습 니 다.
package CoreJava.day_2;

import java.lang.reflect.Field;

/**
 * @author   
 * @date 2016/12/5
 */
public class AssignFieldDemo {
    public static void main(String[] args) {
        try {
            Class c = Class.forName(args[0]);
            Object targetObj = c.newInstance();

            Field testInt = c.getField("testInt");
            testInt.setInt(targetObj, 99);

            Field testString = c.getField("testString");
            testString.set(targetObj, "caterpillar");

            System.out.println(targetObj);
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("     ");
        } catch (ClassNotFoundException e) {
            System.out.println("       ");
        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            System.out.println("          ");
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}

출력:
java AssignFieldDemo CoreJava.day_2.TestField
99:caterpillar

필요 하 다 면 반사 체 제 를 통 해 개인 적 인 구성원 변 수 를 읽 을 수도 있 습 니 다.예 를 들 어:
Field privateField = c.getDeclaredField("privateField"); 
privateField.setAccessible(true);
privateField.setInt(targetObj, 99);

배열 은 자바 에서 배열 도 하나의 대상 이 고 하나의 Class 인 스 턴 스 로 이 를 표시 합 니 다.우 리 는 몇 가지 기본 유형 과 String 으로 테스트 합 니 다.
package CoreJava.day_2;

/**
 * @author   
 * @date 2016/12/5
 */
public class ArrayDemo {
    public static void main(String[] args) {
        short[] sArr = new short[5];
        int[] iArr = new int[5];
        long[] lArr = new long[5];
        float[] fArr = new float[5];
        double[] dArr = new double[5];
        byte[] bArr = new byte[5];
        boolean[] zArr = new boolean[5];
        String[] strArr = new String[5];

        System.out.println("short   :" + sArr.getClass());
        System.out.println("int   :" + iArr.getClass());
        System.out.println("long   :" + lArr.getClass());
        System.out.println("float   :" + fArr.getClass());
        System.out.println("double   :" + dArr.getClass());
        System.out.println("byte   :" + bArr.getClass());
        System.out.println("boolean   :" + zArr.getClass());
        System.out.println("String   :" + strArr.getClass());
    }
}

출력:
shortclass [S
int   :class [I
longclass [J
float   :class [F
doubleclass [D
byteclass [B
booleanclass [Z
Stringclass [Ljava.lang.String;

Process finished with exit code 0

반사 메커니즘 을 사용 하여 동적 으로 배열 을 만 들 려 면 이렇게 할 수도 있다.
package CoreJava.day_2;

import java.lang.reflect.Array;

/**
 * @author   
 * @date 2016/12/5
 */
public class NewArrayDemo {
    public static void main(String[] args) {
        Class c = String.class;
        Object objArr = Array.newInstance(c, 5);

        for (int i = 0; i < 5; i++) {
            Array.set(objArr, i, i + "");
        }

        for (int i = 0; i < 5; i++) {
            System.out.print(Array.get(objArr, i) + " ");
        }
        System.out.println();

        String[] strs = (String[]) objArr;
        for (String s : strs) {
            System.out.print(s + " ");
        }
    }
}

Array.newInstance()의 첫 번 째 매개 변 수 는 지정 한 매개 변수 형식 이 고 두 번 째 매개 변 수 는 배열 의 길 이 를 지정 하 는 데 사 용 됩 니 다.결 과 는 다음 과 같 습 니 다.
0 1 2 3 4
0 1 2 3 4

2 차원 배열 이 라면 마찬가지 입 니 다.
package CoreJava.day_2;

import java.lang.reflect.Array;

/**
 * @author   
 * @date 2016/12/5
 */
public class NewArrayDemo2 {
    public static void main(String[] args) {
        Class c = String.class;

        //       3*4  
        int[] dim = new int[]{3, 4};
        Object objArr = Array.newInstance(c, dim);

        for (int i = 0; i < 3; i++) {
            Object row = Array.get(objArr, i);
            for (int j = 0; j < 4; j++) {
                Array.set(row, j, "" + (i + 1) * (j + 1));
            }
        }

        for (int i = 0; i < 3; i++) {
            Object row = Array.get(objArr, i);
            for (int j = 0; j < 4; j++) {
                System.out.print(Array.get(row, j) + " ");
            }
            System.out.println();
        }
    }
}

출력 결과:
1 2 3 4
2 4 6 8
3 6 9 12

배열 요소 의 종 류 를 알 고 싶다 면 배열 의 Class 인 스 턴 스 를 얻 은 후에 Class 인 스 턴 스 의 getComponent Type()방법 을 사용 하여 요소 의 Class 인 스 턴 스 를 되 찾 을 수 있 습 니 다.예 를 들 어:
int[] iArr = new int[5];
System.out.println(iArr.getClass().getComponentType());

반사 에 대한 정 리 는 많 지 않 아 여기까지 썼 습 니 다.많은 자 료 를 찾 아 보 았 습 니 다.인터넷 에 쓴 것 도 들쭉날쭉 합 니 다.손 으로 쓴 몇 십 개의 demo 기반 에서 얻 은 반사 에 관 한 것 은 모두 정확 하 다 고 말 할 수 없 지만 도움 을 줄 수 있 습 니 다-

좋은 웹페이지 즐겨찾기