2017年12月6日

Java Reflection(反射機制)之一

Java Reflection -1 (反射機制)

Java Reflection最著名例子就是Spring,它帶來XML和Reflection的結合,可以讓開發者可以動態配置資訊、生成物件或是操過物件,何種情況需要使用Java 反射? 讓我們想一想,有些情況是否需要外部的資訊來決定程式的邏輯或是資料,或是有些情況系統之間希望保持低偶合關係。這些你都可以使用反射機制來完成,例如系統可以提供plugin的功能,來擴充系統的檢查功能,這時候可以利用反射不失為一個辦法。

Java Bean 反射範例

POJO物件 以Employee為例一個反射的對象,我們會介紹利用JAVA的反射設機制,如何將類別解析與載入內容。在一個class類架構會有: Method方法、Field屬性、Constructor建構子,如何分別解析並載入內容,是本章節的重點。

/*
*  name: 員工類別的POJO
*/
public class Employee{

    public  Employee(String id){
        this.id = id ;
    }

    public  Employee(String id, String cname){
        this.id = id ;
        this.cname = cname ;
    }

    private String id ; 
    private String cname ; 
    private String sex ;
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public String getCname() {
        return cname;
    }
    public void setCname(String cname) {
        this.cname = cname;
    }
    public String getSex() {
        return sex;
    }
    public void setSex(String sex) {
        this.sex = sex;
    } 

    @Override
    public String toString() {
         return "id:"+id+",cname:"+cname+", sex:"+sex ; 
    }
}

類別反射與載入

類別反射是當我需要使用的類別時,我才做載入的動作,也稱為動態載入。如果是程式啟動時就載入,缺點比較耗資源。所以動態載入會讓系統資源更有效的運用。首先 java.lang.Class 物件代表 在運行時所載入的類別或介面實例,使用Class類別可以取得類別的資訊或是生成實例。

  • Class類別API
函式 說明
public static Class forName(String className) 類別的對象
public T newInstance() 返回一個生成實例
public class TestClass01 {
    public static void main(String[] args) {

        Class<?> c1 = Employee.class ; 
        System.out.println("c1-->"+c1);

        try {
            Class<?> c2 = Class.forName("com.tw.refleciton.Employee") ;
            System.out.println("c2-->"+c2);
            System.out.println("c2-->"+c2.getName());
            System.out.println("c2-->"+c2.getSimpleName());
            System.out.println("c2-->"+c2.getEnclosingClass());
        } catch (ClassNotFoundException e) {

            e.printStackTrace();
        }
    }
}
public class TestClass02 {
    public static void main(String[] args) {

        try {
            Class<?> c3 = Class.forName("com.tw.refleciton.Employee") ;
            Object o1 = c3.newInstance() ; 
            System.out.println("c3-->"+c3);
            System.out.println("o1-->"+o1);

        } catch (ClassNotFoundException e) {

            e.printStackTrace();
        } catch (InstantiationException e) {
            // MARK Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // MARK Auto-generated catch block
            e.printStackTrace();
        }
    }
}

建構子載入

  • Constructor类API
函式 說明
Constructor[] getConstructors() 取得該類別的建構子陣列
Constructor getConstructor(Class… parameterTypes) 符合參數類別,取得建構子對象
T newInstance(Object… initargs) 將內容值設定建構子並生成實例
/*
* name: 取得建構子資訊
*/
public class TestClass03 {
    public static void main(String[] args) {

        try {
            Class<?> c3 = Class.forName("com.tw.refleciton.Employee") ;
            Constructor<?>[] cs = c3.getConstructors();
            for(Constructor<?> c : cs ){
                System.out.print(c.getName()+", parameter size:"+c.getParameterTypes().length);
                Class<?>[] parameters = c.getParameterTypes();
                int i=1 ; 
                if(parameters!=null && parameters.length>0){
                    for(Class<?> p : parameters){
                        System.out.print(",parameter"+i+":"+p.getName()+" , ");
                        i++; 
                    }
                }
                System.out.println();

            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}
結果
com.tw.refleciton.Employee, parameter size:2,parameter1:java.lang.String , ,parameter2:java.lang.String ,
com.tw.refleciton.Employee, parameter size:1,parameter1:java.lang.String ,
/*
 * name:有參數化建構子
 * 利用建構子參數化宣告,必須有參數初始化建構子
 */
public class TestClass04 {
    public static void main(String[] args) {
        try {
            Class<?> c = Class.forName("com.tw.refleciton.Employee") ;
            Constructor<?> cs = c.getConstructor(String.class, String.class);
            Object o = cs.newInstance("0001", "丁大幅") ; 
            System.out.println(o.toString());

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            // MARK Auto-generated catch block
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            // MARK Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            // MARK Auto-generated catch block
            e.printStackTrace();
        } catch (InstantiationException e) {
            // MARK Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // MARK Auto-generated catch block
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            // MARK Auto-generated catch block
            e.printStackTrace();
        } 
    }
}
結果
id:0001,cname:丁大幅, sex:nul

屬性載入

  • 屬性常用的API
函式 說明
Field[] getDeclaredFields() 取得所有屬性
Field getDeclaredField(String name) 取得指定的屬性
void set(Object obj, Object value) 設定屬性的新內容值
Object get(Object obj) 取得屬性的內容值
void setAccessible(boolean flag) 設定該屬性是否可以訪問true: 可以訪問、false : 不可以訪問
boolean isAccessible() 該屬性是否可以訪問true: 可以訪問、false : 不可以訪問


/**
 * name:解析field的欄位名稱
 */
public class TestClass05 {

    public static void main(String[] args) {

        try {
            Class<?> c5 = Class.forName("com.tw.refleciton.Employee") ;
            Field[] fs = c5.getDeclaredFields() ; 
            if(fs.length>0){
                for(Field f: fs){
                    System.out.println("field:"+f.getName());
                }

            }

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}
結果
name:sex,value –>> 男id:0002,cname:王大明, sex:男

參考

  1. https://github.com/JustinSDK/JavaSE6Tutorial/blob/master/docs/CH16.md
  2. Java反射机制连载(1)– JavaBean
  3. Java反射机制连载(2)– Class类
  4. Java反射机制连载(3)– Constructor类
  5. Java反射机制连载(4)– Field类
  6. Java反射机制连载(5)– Method类
  7. Java反射机制连载(6)– PropertyDescriptor类
  8. Java反射机制连载(7)– 使用反射实现的ORM持久层框架 attachment
  9. Java反射机制连载(7)– 使用反射实现的ORM持久层框架 attachment
  10. Java反射机制连载(9)– 自定义持久层框架之JdbcOperations接口

沒有留言:

張貼留言