2016年12月17日 星期六

為屬性、方法設值取值(反射四)

※屬性設值取值

package inheritate;
    
public class Son {
    public String s1;
    private String s2;
}
------------------------------
public static void main(String[] args) throws Exception {
    Class<?> clazz = Class.forName("inheritate.Son");
    
    Field s1 = clazz.getField("s1");
    Object s1Obj = clazz.newInstance();
    s1.set(s1Obj, "xxx");
    System.out.println(s1.get(s1Obj));
    
    // Field s2 = clazz.getField("s2");
    Field s2 = clazz.getDeclaredField("s2");
    s2.setAccessible(true);
    Object s2Obj = clazz.newInstance();
    s2.set(s2Obj, "ooo");
    System.out.println(s2.get(s2Obj));
}

※修飾子不是public的,有可能會報「NoSuchFieldException」的錯,得看測試類在放在哪而定

※想取得上面報的錯的值,可用setAccessible,但得用DeclaredField才行,不然還是會報錯,因為DeclaredField本來就是取自己class的東西



※AccessibleObject.setAccessible

Field和Method到最後都會繼承AccessibleObject類別,所以setAccessible都可以用
setAccessible是個overloadding,有分一個參數和兩個參數,兩個參數是static的
一個參數上個例子已有,這裡講的是兩個參數的


package inheritate;
    
public class Son {
    private String s0;
    private String s1;
    private String s2;
    private String s3;
    private String s4;
}
------------------------------
public static void main(String[] args) throws Exception {
    Class<?> clazz = Class.forName("inheritate.Son");
    
    Field[] fields = clazz.getDeclaredFields();
    Object obj = clazz.newInstance();
    for (int i = 0; i < fields.length; i++) {
        fields[i].setAccessible(true);
        fields[i].set(obj, "s" + i);
        System.out.println("field name=" + fields[i].getName());
        System.out.println("field value=" + fields[i].get(obj));
        System.out.println();
    }
}

※這個例子還是和上個例子一樣,跑迴圈時,一個一個變成true


Class<?> clazz = Class.forName("inheritate.Son");
    
Field[] fields = clazz.getDeclaredFields();
AccessibleObject.setAccessible(fields, true);
Object obj = clazz.newInstance();
for (int i = 0; i < fields.length; i++) {
    // f.setAccessible(fields, true);
    fields[i].set(obj, "s" + i);
    System.out.println("field name=" + fields[i].getName());
    System.out.println("field value=" + fields[i].get(obj));
    System.out.println();
}

※使用靜態方法可以一次將屬性全部變成true

※註解那行也是可以,但浪費一些資源,而且會有警告,因為它是static


※方法設值取值

package inheritate;
    
public class Son {
    public String sayHello() {
        return "hello";
    }
    
    public String say(String data) {
        return data;
    }
    
    private String privateTest() {
        return "private method";
    }
}
------------------------------
public static void main(String[] args) throws Exception {
    Class<?> clazz = Class.forName("inheritate.Son");
    
    // 呼叫無參方法
    Method m1 = clazz.getMethod("sayHello");
    String r1 = (String) m1.invoke(clazz.newInstance());
    System.out.println(r1);
    
    // 呼叫有參方法
    Method m2 = clazz.getMethod("say", String.class);
    String r2 = (String) m2.invoke(clazz.newInstance(), "Hello Reflection");
    System.out.println(r2);
    
    // 取得private方法
    // Method m3 = clazz.getMethod("privateTest");
    Method m3 = clazz.getDeclaredMethod("privateTest");
    m3.setAccessible(true);
    String r3 = (String) m3.invoke(clazz.newInstance());
    System.out.println(r3);
}

※修飾子不是public的,有可能會報「NoSuchMethodException」的錯,得看測試類在放在哪而定

※想取得上面報的錯的值,可用setAccessible,但得用DeclaredMethod才行,不然還是會報錯,因為DeclaredField本來就是取自己class的東西

※invoke就是呼叫方法了,裡面至少要放實體,如果沒有回傳值也不會報錯,會回傳null



※setter/getter

package inheritate;
    
public class Son {
    private int id;
    
    public int getId() {
        return id;
    }
    
    public void setId(int id) {
        this.id = id;
    }
}
------------------------------
public static void main(String[] args) throws Exception {
    Class<?> clazz = Class.forName("inheritate.Son");
    
    Object obj = clazz.newInstance();
    Class<?> cz = obj.getClass();
    
    Method m1 = cz.getMethod("setId", int.class);
    m1.invoke(obj, 1);
    
    Method m2 = cz.getMethod("getId");
    Object getResult = m2.invoke(obj);
    System.out.println(getResult);
}

※使用newInstance取得實體,然後再取得Class,這個Class可以讓setter/getter使用



※setter/getter公用方法

public static void main(String[] args) throws Exception {
    Class<?> clazz = Class.forName("inheritate.Son");
    
    Object obj = clazz.newInstance();
    Class<?> cz = obj.getClass();
    
    setXxx(cz, obj, "id", int.class, 1);
    int rtn = (int) getXxx(cz, obj, "id");
    System.out.println(rtn);
}
    
public static <T> void setXxx(Class<?> sourceClass, Object instance, String methodName, Class<T> parameterType, T value) throws Exception {
    Method m = sourceClass.getMethod("set" + firstUpperCase(methodName), parameterType);
    m.invoke(instance, value);
}
    
public static String firstUpperCase(String methodName) {
    return methodName.substring(0, 1).toUpperCase() + methodName.substring(1);
}
    
public static Object getXxx(Class<?> sourceClass, Object instance, String methodName) throws Exception {
    Method m = sourceClass.getMethod("get" + firstUpperCase(methodName));
    return m.invoke(instance);
}

沒有留言:

張貼留言