跳到主要內容

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接口

留言

這個網誌中的熱門文章

GSON基礎教學

GSON 前言 JSON是很常見的資料交換格式,在JAVA領域常用處理JSON的函式庫:GSON、FastXML和JSON-B,本章節會以GSON為主,學習目標如下 JSON格式說明 GSON 套件函式 GSON: 物件轉換JSON字串 GSON: JSON字串轉換物件 JSON 格式說明 JSON全名為JavaScript Object Notation,它是一種輕量級的資料交換格式,會大為流行的理由,主要是他比傳統用xml更輕巧且容易處理, JSON表達方式物件會用大括弧{},陣列則是用中括號[]。 用JSON字串來表達Employee的物件內容,由JSON字串可以知道物件name、age、sex和salary屬性。 JSON表示員工資料方式: {“name”:”Jack Bryant”, “age”:18, “sex”:”M”,”salary”:3500.00} JSON陣列表示方式: 跟我們使用JAVA的陣列方式類似,內容值可以是數字’、文字、布林、陣列、物件、null等等。 範例: 字串: [“紅”、”橙”、”黃”、”綠”、”青”、”藍”、”紫”} 布林: [true, true, false, false, true, true] GSON 套件函式 Gson為google所發布的函式庫,主要將物件與json字串之間的轉換時方便使用。當我們將JAVA物件轉換成JSON字串稱為 序列化 ,JSON字串轉換至JAVA物件稱為 反序列化 。 GSON: 物件轉換JSON字串 有了JSON基本概念後,我們進入本章重點,首先我們需要建立員工類別(Employee),定義如下 物件 屬性 員工類別 Employee name 名字 age 年紀 sex 性別 salary 薪水 /** * name:員工類別 */ public class Employee implements Serializable { //constructor public Employee(String name, double salary){ this.name = name; this.sala...

PHP與Python搭配

今天介紹如何利用php網頁呼叫目錄下的python程式工作或是資料交換,本人整理的方法有兩種 使用system()、exec()、shell_exec()呼叫程式 (1) string system ( string return_var ] ) 參考網址 官網解釋system()用來執行外部命令,返回為印出的結果,passthru()跟system()類似但是它不會返回結果。 範例1. 利用system執行ls指定並顯示在網頁上,無法使用變數保留ls的結果 檔案名稱: psystem.php $jsondata= system("ls -al", $result); 結果: (2) exec() : string exec ( string output [, int &$return_var ]] ) 參考網址 範例2. 利用exec執行python程式並可以回傳json格式給前端網頁做處理並顯示。我們ptopy.php就是可以看到callpy()為執行py的函式,它執行完pyEx01.py會將結果給$jsondata變數,做後面json解析。 檔案名稱: ptopy.php function callpy() { $jsondata= exec("/usr/bin/python pyEx01.py"); return $jsondata ; } $jsondata= callpy(); echo $jsondata ; echo " " ; $obj = json_decode($jsondata) ; echo "name:".$obj-> { 'name'} .',' ; echo "id:".$obj-> { 'id'} ; 檔案名稱: pyEx01.py import sys ...

Python AI-問題集

Python AI-問題集 問題集 Jupyter Notebook執行ipywidgets會出現kernel死掉的錯誤發生(The kernel appears to have died) 解決方法 (1) 根據log檔來判斷問題: 例如:log訊息出現OMP: Error #15: Initializing libiomp5.dylib, but found libiomp5.dylib already initialized. (2) 根據問題關鍵字找出問題所在: 利用google查詢所遭遇到的問題,例如我把上面的問題上google查詢可以找到這篇的解法 https://blog.csdn.net/bingjianIT/article/details/86182096 (3)實作解法: 我實作下面解法後,就可以順利執行手寫辨識的程式. //在Python宣告時加入 import os os.environ["KMP_DUPLICATE_LIB_OK"]="TRUE" 參考 https://blog.csdn.net/bingjianIT/article/details/86182096