Java反射機制詳解

1反射機制是什么

反射機制是在運行狀態(tài)中锨推,對于任意一個類,都能夠知道這個類的所有屬性和方法余佃;對于任意一個對象蔽氨,都能夠調(diào)用它的任意一個方法和屬性藐唠;這種動態(tài)獲取的信息以及動態(tài)調(diào)用對象的方法的功能稱為java語言的反射機制帆疟。

2反射機制能做什么

1.反射機制主要提供了以下功能:

2.在運行時判斷任意一個對象所屬的類;

3.在運行時構(gòu)造任意一個類的對象宇立;

4.在運行時判斷任意一個類所具有的成員變量和方法踪宠;

5.在運行時調(diào)用任意一個對象的方法;

6.生成動態(tài)代理泄伪。

3反射機制的相關API

通過一個對象獲得完整的包名和類名

package net.xsoftlab.baike;
public class TestReflect {
    public static void main(String[] args) throws Exception {
        TestReflect testReflect = new TestReflect();
        System.out.println(testReflect.getClass().getName());
        // 結(jié)果 net.xsoftlab.baike.TestReflect
    }
}

實例化Class類對象

package net.xsoftlab.baike;
public class TestReflect {
   public static void main(String[] args) throws Exception {
       Class<?> class1 = null;
       Class<?> class2 = null;
       Class<?> class3 = null;
       // 一般采用這種形式
       class1 = Class.forName("net.xsoftlab.baike.TestReflect");
       class2 = new TestReflect().getClass();
       class3 = TestReflect.class;
       System.out.println("類名稱   " + class1.getName());
       System.out.println("類名稱   " + class2.getName());
       System.out.println("類名稱   " + class3.getName());
   }
}

獲取一個對象的父類與實現(xiàn)的接口

package net.xsoftlab.baike;
import java.io.Serializable;
public class TestReflect implements Serializable {
    private static final long serialVersionUID = -2862585049955236662L;
    public static void main(String[] args) throws Exception {
        Class<?> clazz = Class.forName("net.xsoftlab.baike.TestReflect");
        // 取得父類
        Class<?> parentClass = clazz.getSuperclass();
        System.out.println("clazz的父類為:" + parentClass.getName());
        // clazz的父類為: java.lang.Object
        // 獲取所有的接口
        Class<?> intes[] = clazz.getInterfaces();
        System.out.println("clazz實現(xiàn)的接口有:");
        for (int i = 0; i < intes.length; i++) {
            System.out.println((i + 1) + ":" + intes[i].getName());
        }
        // clazz實現(xiàn)的接口有:
        // 1:java.io.Serializable
    }
}

獲取某個類中的全部構(gòu)造函數(shù) - 詳見下例

通過反射機制實例化一個類的對象

package net.xsoftlab.baike;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
public class TestReflect implements Serializable {
    private static final long serialVersionUID = -2862585049955236662L;
    public static void main(String[] args) throws Exception {
        Class<?> clazz = Class.forName("net.xsoftlab.baike.TestReflect");
        System.out.println("===============本類屬性===============");
        // 取得本類的全部屬性
        Field[] field = clazz.getDeclaredFields();
        for (int i = 0; i < field.length; i++) {
            // 權(quán)限修飾符
            int mo = field[i].getModifiers();
            String priv = Modifier.toString(mo);
            // 屬性類型
            Class<?> type = field[i].getType();
            System.out.println(priv + " " + type.getName() + " " + field[i].getName() + ";");
        }
         
        System.out.println("==========實現(xiàn)的接口或者父類的屬性==========");
        // 取得實現(xiàn)的接口或者父類的屬性
        Field[] filed1 = clazz.getFields();
        for (int j = 0; j < filed1.length; j++) {
            // 權(quán)限修飾符
            int mo = filed1[j].getModifiers();
            String priv = Modifier.toString(mo);
            // 屬性類型
            Class<?> type = filed1[j].getType();
            System.out.println(priv + " " + type.getName() + " " + filed1[j].getName() + ";");
        }
    }
}

獲取某個類的全部屬性

package net.xsoftlab.baike;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
public class TestReflect implements Serializable {
    private static final long serialVersionUID = -2862585049955236662L;
    public static void main(String[] args) throws Exception {
        Class<?> clazz = Class.forName("net.xsoftlab.baike.TestReflect");
        System.out.println("===============本類屬性===============");
        // 取得本類的全部屬性
        Field[] field = clazz.getDeclaredFields();
        for (int i = 0; i < field.length; i++) {
            // 權(quán)限修飾符
            int mo = field[i].getModifiers();
            String priv = Modifier.toString(mo);
            // 屬性類型
            Class<?> type = field[i].getType();
            System.out.println(priv + " " + type.getName() + " " + field[i].getName() + ";");
        }
         
        System.out.println("==========實現(xiàn)的接口或者父類的屬性==========");
        // 取得實現(xiàn)的接口或者父類的屬性
        Field[] filed1 = clazz.getFields();
        for (int j = 0; j < filed1.length; j++) {
            // 權(quán)限修飾符
            int mo = filed1[j].getModifiers();
            String priv = Modifier.toString(mo);
            // 屬性類型
            Class<?> type = filed1[j].getType();
            System.out.println(priv + " " + type.getName() + " " + filed1[j].getName() + ";");
        }
    }
}

獲取某個類的全部方法

package net.xsoftlab.baike;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
public class TestReflect implements Serializable {
    private static final long serialVersionUID = -2862585049955236662L;
    public static void main(String[] args) throws Exception {
        Class<?> clazz = Class.forName("net.xsoftlab.baike.TestReflect");
        Method method[] = clazz.getMethods();
        for (int i = 0; i < method.length; ++i) {
            Class<?> returnType = method[i].getReturnType();
            Class<?> para[] = method[i].getParameterTypes();
            int temp = method[i].getModifiers();
            System.out.print(Modifier.toString(temp) + " ");
            System.out.print(returnType.getName() + "  ");
            System.out.print(method[i].getName() + " ");
            System.out.print("(");
            for (int j = 0; j < para.length; ++j) {
                System.out.print(para[j].getName() + " " + "arg" + j);
                if (j < para.length - 1) {
                    System.out.print(",");
                }
            }
            Class<?> exce[] = method[i].getExceptionTypes();
            if (exce.length > 0) {
                System.out.print(") throws ");
                for (int k = 0; k < exce.length; ++k) {
                    System.out.print(exce[k].getName() + " ");
                    if (k < exce.length - 1) {
                        System.out.print(",");
                    }
                }
            } else {
                System.out.print(")");
            }
            System.out.println();
        }
    }
}

通過反射機制調(diào)用某個類的方法

package net.xsoftlab.baike;
import java.lang.reflect.Method;
public class TestReflect {
    public static void main(String[] args) throws Exception {
        Class<?> clazz = Class.forName("net.xsoftlab.baike.TestReflect");
        // 調(diào)用TestReflect類中的reflect1方法
        Method method = clazz.getMethod("reflect1");
        method.invoke(clazz.newInstance());
        // Java 反射機制 - 調(diào)用某個類的方法1.
        // 調(diào)用TestReflect的reflect2方法
        method = clazz.getMethod("reflect2", int.class, String.class);
        method.invoke(clazz.newInstance(), 20, "張三");
        // Java 反射機制 - 調(diào)用某個類的方法2.
        // age -> 20. name -> 張三
    }
    public void reflect1() {
        System.out.println("Java 反射機制 - 調(diào)用某個類的方法1.");
    }
    public void reflect2(int age, String name) {
        System.out.println("Java 反射機制 - 調(diào)用某個類的方法2.");
        System.out.println("age -> " + age + ". name -> " + name);
    }
}

通過反射機制操作某個類的屬性

package net.xsoftlab.baike;
import java.lang.reflect.Field;
public class TestReflect {
    private String proprety = null;
    public static void main(String[] args) throws Exception {
        Class<?> clazz = Class.forName("net.xsoftlab.baike.TestReflect");
        Object obj = clazz.newInstance();
        // 可以直接對 private 的屬性賦值
        Field field = clazz.getDeclaredField("proprety");
        field.setAccessible(true);
        field.set(obj, "Java反射機制");
        System.out.println(field.get(obj));
    }
}

反射機制的動態(tài)代理

// 獲取類加載器的方法
TestReflect testReflect = new TestReflect();
        System.out.println("類加載器  " + testReflect.getClass().getClassLoader().getClass().getName());
package net.xsoftlab.baike;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//定義項目接口
interface Subject {
    public String say(String name, int age);
}
// 定義真實項目
class RealSubject implements Subject {
    public String say(String name, int age) {
        return name + "  " + age;
    }
}
class MyInvocationHandler implements InvocationHandler {
    private Object obj = null;
    public Object bind(Object obj) {
        this.obj = obj;
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this);
    }
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object temp = method.invoke(this.obj, args);
        return temp;
    }
}
/**
 * 在java中有三種類類加載器殴蓬。
 * 
 * 1)Bootstrap ClassLoader 此加載器采用c++編寫,一般開發(fā)中很少見蟋滴。
 * 
 * 2)Extension ClassLoader 用來進行擴展類的加載染厅,一般對應的是jrelibext目錄中的類
 * 
 * 3)AppClassLoader 加載classpath指定的類,是最常用的加載器津函。同時也是java中默認的加載器肖粮。
 * 
 * 如果想要完成動態(tài)代理,首先需要定義一個InvocationHandler接口的子類尔苦,已完成代理的具體操作涩馆。
 * 
 * @author xsoftlab.net
 * 
 */
public class TestReflect {
    public static void main(String[] args) throws Exception {
        MyInvocationHandler demo = new MyInvocationHandler();
        Subject sub = (Subject) demo.bind(new RealSubject());
        String info = sub.say("Rollen", 20);
        System.out.println(info);
    }
}

4反射機制的應用實例

在泛型為Integer的ArrayList中存放一個String類型的對象。

package net.xsoftlab.baike;
import java.lang.reflect.Method;
import java.util.ArrayList;
public class TestReflect {
    public static void main(String[] args) throws Exception {
        ArrayList<Integer> list = new ArrayList<Integer>();
        Method method = list.getClass().getMethod("add", Object.class);
        method.invoke(list, "Java反射機制實例允坚。");
        System.out.println(list.get(0));
    }
}

通過反射取得并修改數(shù)組的信息

package net.xsoftlab.baike;
import java.lang.reflect.Array;
public class TestReflect {
    public static void main(String[] args) throws Exception {
        int[] temp = { 1, 2, 3, 4, 5 };
        Class<?> demo = temp.getClass().getComponentType();
        System.out.println("數(shù)組類型: " + demo.getName());
        System.out.println("數(shù)組長度  " + Array.getLength(temp));
        System.out.println("數(shù)組的第一個元素: " + Array.get(temp, 0));
        Array.set(temp, 0, 100);
        System.out.println("修改之后數(shù)組第一個元素為: " + Array.get(temp, 0));
    }
}

通過反射機制修改數(shù)組的大小

package net.xsoftlab.baike;
import java.lang.reflect.Array;
public class TestReflect {
    public static void main(String[] args) throws Exception {
        int[] temp = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
        int[] newTemp = (int[]) arrayInc(temp, 15);
        print(newTemp);
        String[] atr = { "a", "b", "c" };
        String[] str1 = (String[]) arrayInc(atr, 8);
        print(str1);
    }
    // 修改數(shù)組大小
    public static Object arrayInc(Object obj, int len) {
        Class<?> arr = obj.getClass().getComponentType();
        Object newArr = Array.newInstance(arr, len);
        int co = Array.getLength(obj);
        System.arraycopy(obj, 0, newArr, 0, co);
        return newArr;
    }
    // 打印
    public static void print(Object obj) {
        Class<?> c = obj.getClass();
        if (!c.isArray()) {
            return;
        }
        System.out.println("數(shù)組長度為: " + Array.getLength(obj));
        for (int i = 0; i < Array.getLength(obj); i++) {
            System.out.print(Array.get(obj, i) + " ");
        }
        System.out.println();
    }
}

將反射機制應用于工廠模式

package net.xsoftlab.baike;
interface fruit {
    public abstract void eat();
}
class Apple implements fruit {
    public void eat() {
        System.out.println("Apple");
    }
}
class Orange implements fruit {
    public void eat() {
        System.out.println("Orange");
    }
}
class Factory {
    public static fruit getInstance(String ClassName) {
        fruit f = null;
        try {
            f = (fruit) Class.forName(ClassName).newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return f;
    }
}
/**
 * 對于普通的工廠模式當我們在添加一個子類的時候魂那,就需要對應的修改工廠類。 當我們添加很多的子類的時候稠项,會很麻煩涯雅。
 * Java 工廠模式可以參考
 * http://baike.xsoftlab.net/view/java-factory-pattern
 * 
 * 現(xiàn)在我們利用反射機制實現(xiàn)工廠模式,可以在不修改工廠類的情況下添加任意多個子類展运。
 * 
 * 但是有一點仍然很麻煩活逆,就是需要知道完整的包名和類名,這里可以使用properties配置文件來完成拗胜。
 * 
 * java 讀取 properties 配置文件 的方法可以參考
 * http://baike.xsoftlab.net/view/java-read-the-properties-configuration-file
 * 
 * @author xsoftlab.net
 */
public class TestReflect {
    public static void main(String[] args) throws Exception {
        fruit f = Factory.getInstance("net.xsoftlab.baike.Apple");
        if (f != null) {
            f.eat();
        }
    }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末蔗候,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子埂软,更是在濱河造成了極大的恐慌锈遥,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,723評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件勘畔,死亡現(xiàn)場離奇詭異迷殿,居然都是意外死亡,警方通過查閱死者的電腦和手機咖杂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蚊夫,“玉大人诉字,你說我怎么就攤上這事。” “怎么了壤圃?”我有些...
    開封第一講書人閱讀 152,998評論 0 344
  • 文/不壞的土叔 我叫張陵陵霉,是天一觀的道長。 經(jīng)常有香客問我伍绳,道長踊挠,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,323評論 1 279
  • 正文 為了忘掉前任冲杀,我火速辦了婚禮效床,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘权谁。我一直安慰自己剩檀,他們只是感情好,可當我...
    茶點故事閱讀 64,355評論 5 374
  • 文/花漫 我一把揭開白布旺芽。 她就那樣靜靜地躺著沪猴,像睡著了一般。 火紅的嫁衣襯著肌膚如雪采章。 梳的紋絲不亂的頭發(fā)上运嗜,一...
    開封第一講書人閱讀 49,079評論 1 285
  • 那天,我揣著相機與錄音悯舟,去河邊找鬼担租。 笑死,一個胖子當著我的面吹牛图谷,可吹牛的內(nèi)容都是我干的翩活。 我是一名探鬼主播,決...
    沈念sama閱讀 38,389評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼便贵,長吁一口氣:“原來是場噩夢啊……” “哼菠镇!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起承璃,我...
    開封第一講書人閱讀 37,019評論 0 259
  • 序言:老撾萬榮一對情侶失蹤利耍,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后盔粹,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體隘梨,經(jīng)...
    沈念sama閱讀 43,519評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,971評論 2 325
  • 正文 我和宋清朗相戀三年舷嗡,在試婚紗的時候發(fā)現(xiàn)自己被綠了轴猎。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,100評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡进萄,死狀恐怖捻脖,靈堂內(nèi)的尸體忽然破棺而出锐峭,到底是詐尸還是另有隱情,我是刑警寧澤可婶,帶...
    沈念sama閱讀 33,738評論 4 324
  • 正文 年R本政府宣布沿癞,位于F島的核電站,受9級特大地震影響矛渴,放射性物質(zhì)發(fā)生泄漏椎扬。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,293評論 3 307
  • 文/蒙蒙 一具温、第九天 我趴在偏房一處隱蔽的房頂上張望蚕涤。 院中可真熱鬧,春花似錦桂躏、人聲如沸钻趋。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蛮位。三九已至,卻和暖如春鳞绕,著一層夾襖步出監(jiān)牢的瞬間失仁,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評論 1 262
  • 我被黑心中介騙來泰國打工们何, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留萄焦,地道東北人。 一個月前我還...
    沈念sama閱讀 45,547評論 2 354
  • 正文 我出身青樓冤竹,卻偏偏與公主長得像拂封,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子鹦蠕,可洞房花燭夜當晚...
    茶點故事閱讀 42,834評論 2 345

推薦閱讀更多精彩內(nèi)容

  • 1.理解反射的基礎:Class類 眾所周知Java有個Object 類冒签,是所有Java 類的繼承根源,其內(nèi)聲明了數(shù)...
    Cat9527閱讀 534評論 1 5
  • 對于一般的開發(fā)者钟病,很少需要直接使用Java反射機制來完成功能開發(fā)萧恕,但是反射是很多框架譬如 Spring, Myba...
    小旋鋒的簡書閱讀 1,960評論 0 9
  • 前言 Java反射機制很早的時候就有耳聞肠阱,期間也會去看看相關資料票唆,但是又很快會忘記,所以屹徘,寫一篇Blog來加深記憶...
    Android_Simon閱讀 509評論 0 1
  • 接下來我們將介紹Java反射機制的一系列的知識走趋。本篇文章主要針對Java反射機制的介紹以及反射API的使用知識。 ...
    Ruheng閱讀 7,515評論 3 65
  • 寫在前面的話:很多人會說我直接new一個對象不就完了么噪伊,干嘛還用反射來獲取對象吆视。因為new屬于靜態(tài)編譯典挑,而反射屬于...
    iDaniel閱讀 8,606評論 1 4