2016年12月11日 星期日

Class、塞值 (反射一)

※Class取得方式

System.out.println("1.使用Object物件的getClass()");
Class<? extends BigDecimal> c1 = BigDecimal.ZERO.getClass();
System.out.println(c1 + System.getProperty("line.separator"));
    
System.out.println("2.使用.class");
Class<Integer> c2a = int.class;
Class<Integer> c2b = Integer.class;
System.out.println(c2a);
System.out.println(c2b + System.getProperty("line.separator"));
    
System.out.println("3.使用Class.forName()");
try {
    Class<?> c3 = Class.forName("java.util.List");
    System.out.println(c3 + System.getProperty("line.separator"));
} catch (ClassNotFoundException e) {
    e.printStackTrace();
}
    
System.out.println("4.Wrapper類別才有的TYPE");
Class<Long> c4 = Long.TYPE;
System.out.println(c4);

※結果:
1.使用Object物件的getClass()
class java.math.BigDecimal

2.使用.class
int
class java.lang.Integer

3.使用Class.forName()
interface java.util.List

4.Wrapper類別才有的TYPE
long

※第2種泛型裡只能是Wrapper類別,但都能分清楚

※第4種取得的是小寫的


※塞值的四種方式

package xxx.ooo;
    
public class JavaBean {
    private int id;
    private String name;
    
    // setter/getter...
}

※隨便寫一隻java bean


※四種方式
try {
    System.out.println("原本的方式");
    JavaBean jb1 = new JavaBean();
    jb1.setId(1);
    jb1.setName("George");
    System.out.println(jb1.getId());
    System.out.println(jb1.getName());
    
    System.out.println(System.getProperty("line.separator") + "Java8的lambda方式");
    Supplier<JavaBean> sup = () -> {
        return new JavaBean();
    };
    JavaBean jb2 = sup.get();
    jb2.setId(2);
    jb2.setName("Mary");
    System.out.println(jb2.getId());
    System.out.println(jb2.getName());
    
    System.out.println(System.getProperty("line.separator") + "Java8的引用方式");
    Supplier<JavaBean> supp = JavaBean::new;
    JavaBean jb3 = supp.get();
    jb3.setId(3);
    jb3.setName("借錢");
    System.out.println(jb3.getId());
    System.out.println(jb3.getName());
    
    System.out.println(System.getProperty("line.separator") + "反射的方式");
    Class<?> c3 = Class.forName("xxx.ooo.JavaBean");
    JavaBean jb4 = (JavaBean) c3.newInstance();
    jb4.setId(4);
    jb4.setName("免還");
    System.out.println(jb4.getId());
    System.out.println(jb4.getName());
} catch (ClassNotFoundException e) {
    e.printStackTrace();
} catch (InstantiationException e) {
    e.printStackTrace();
} catch (IllegalAccessException e) {
    e.printStackTrace();
}

※可以很順利的塞值,但反射的方式看不出來有用預設建構子,其實是有用到的,如在JavaBean增加一個建構子,如下:


public class JavaBean {
    private int id;
    private String name;
    
    public JavaBean(int id, String name) {
        this.id = id;
        this.name = name;
    }
    
    // setter/getter...
}

※此時預設建構子就會消失,這時反射的方式在編譯時不會報錯,執行時會報「java.lang.NoSuchMethodException: xxx.ooo.JavaBean.<init>()」的錯,所以大部分寫java bean時都會要求一定要有預設建構子

※雖然沒有預設建構子,但反射還是能做到塞值的功能,如下:


try {
    System.out.println("原本的方式");
    JavaBean jb1 = new JavaBean(1, "George");
    System.out.println(jb1.getId());
    System.out.println(jb1.getName());
    
    System.out.println(System.getProperty("line.separator") + "Java8的lambda方式");
    BiFunction<Integer, String, JavaBean> bf = (i, s) -> {
        return new JavaBean(i, s);
    };
    JavaBean jb2 = bf.apply(2, "Mary");
    System.out.println(jb2.getId());
    System.out.println(jb2.getName());
    
    System.out.println(System.getProperty("line.separator") + "Java8的引用方式");
    BiFunction<Integer, String, JavaBean> bif = JavaBean::new;
    JavaBean jb3 = bif.apply(3, "借錢");
    System.out.println(jb3.getId());
    System.out.println(jb3.getName());
    
    System.out.println(System.getProperty("line.separator") + "反射的方式");
    Class<?> c3 = Class.forName("xxx.ooo.JavaBean");
    // JavaBean jb4 = (JavaBean) c3.newInstance();
    // jb4.setId(4);
    // jb4.setName("免還");
    
    Constructor<?>[] conArray = c3.getConstructors();
    JavaBean jb4 = null;
    try {
        jb4 = (JavaBean) conArray[0].newInstance(4, "免還");
    } catch (IllegalArgumentException | InvocationTargetException e) {
        e.printStackTrace();
    }
    System.out.println(jb4.getId());
    System.out.println(jb4.getName());
} catch (ClassNotFoundException e) {
    e.printStackTrace();
} catch (InstantiationException e) {
    e.printStackTrace();
} catch (IllegalAccessException e) {
    e.printStackTrace();
}

※反射的方式要利用getConstructors()的方法就可以做到塞值



※不用 set 的塞值

這種方法可以在迴圈判斷方法名時加數字

Animal animal = new Animal();

Stream.of(animal.getClass().getDeclaredMethods()).forEach(m -> {
if (m.getName().equals("setName")) {
try {
m.invoke(animal, "monkey");
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
}
});
System.out.println(animal.getName());

沒有留言:

張貼留言