Java反射基礎(chǔ)詳解

Java反射機制

反射機制是什么

反射機制是在運行狀態(tài)中档玻,對于任意一個類,都能夠知道這個類的所有屬性和方法本砰;對于任意一個對象,都能夠調(diào)用它的任意一個方法和屬性仅讽;這種動態(tài)獲取的信息以及動態(tài)調(diào)用對象的方法的功能稱為java語言的反射機制陶缺。

反射機制能做什么

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

  • 在運行時判斷任意一個對象所屬的類;
  • 在運行時構(gòu)造任意一個類的對象洁灵;
  • 在運行時判斷任意一個類所具有的成員變量和方法饱岸;
  • 在運行時調(diào)用任意一個對象的方法;
  • 生成動態(tài)代理处渣。

反射機制的相關(guān)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.lang.reflect.Constructor;
public class TestReflect {
    public static void main(String[] args) throws Exception {
        Class<?> class1 = null;
        class1 = Class.forName("net.xsoftlab.baike.User");
        // 第一種方法伶贰,實例化默認構(gòu)造方法,調(diào)用set賦值
        User user = (User) class1.newInstance();
        user.setAge(20);
        user.setName("Rollen");
        System.out.println(user);
        // 結(jié)果 User [age=20, name=Rollen]
        // 第二種方法 取得全部的構(gòu)造函數(shù) 使用構(gòu)造函數(shù)賦值
        Constructor<?> cons[] = class1.getConstructors();
        // 查看每個構(gòu)造方法需要的參數(shù)
        for (int i = 0; i < cons.length; i++) {
            Class<?> clazzs[] = cons[i].getParameterTypes();
            System.out.print("cons[" + i + "] (");
            for (int j = 0; j < clazzs.length; j++) {
                if (j == clazzs.length - 1)
                    System.out.print(clazzs[j].getName());
                else
                    System.out.print(clazzs[j].getName() + ",");
            }
            System.out.println(")");
        }
        // 結(jié)果
        // cons[0] (java.lang.String)
        // cons[1] (int,java.lang.String)
        // cons[2] ()
        user = (User) cons[0].newInstance("Rollen");
        System.out.println(user);
        // 結(jié)果 User [age=0, name=Rollen]
        user = (User) cons[1].newInstance(20, "Rollen");
        System.out.println(user);
        // 結(jié)果 User [age=20, name=Rollen]
    }
}
class User {
    private int age;
    private String name;
    public User() {
        super();
    }
    public User(String name) {
        super();
        this.name = name;
    }
    public User(int age, String name) {
        super();
        this.age = age;
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return "User [age=" + age + ", name=" + name + "]";
    }
}

獲取某個類的全部屬性

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);
    }
}

反射機制的應用實例

在泛型為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();
        }
    }
}

轉(zhuǎn)自Java反射機制詳解

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末避咆,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子静秆,更是在濱河造成了極大的恐慌牵素,老刑警劉巖严衬,帶你破解...
    沈念sama閱讀 217,907評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異两波,居然都是意外死亡瞳步,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,987評論 3 395
  • 文/潘曉璐 我一進店門腰奋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來单起,“玉大人,你說我怎么就攤上這事劣坊∴值梗” “怎么了?”我有些...
    開封第一講書人閱讀 164,298評論 0 354
  • 文/不壞的土叔 我叫張陵局冰,是天一觀的道長测蘑。 經(jīng)常有香客問我,道長康二,這世上最難降的妖魔是什么碳胳? 我笑而不...
    開封第一講書人閱讀 58,586評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮沫勿,結(jié)果婚禮上挨约,老公的妹妹穿的比我還像新娘。我一直安慰自己产雹,他們只是感情好诫惭,可當我...
    茶點故事閱讀 67,633評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著蔓挖,像睡著了一般夕土。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上瘟判,一...
    開封第一講書人閱讀 51,488評論 1 302
  • 那天怨绣,我揣著相機與錄音,去河邊找鬼荒适。 笑死梨熙,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的刀诬。 我是一名探鬼主播咽扇,決...
    沈念sama閱讀 40,275評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼陕壹!你這毒婦竟也來了质欲?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,176評論 0 276
  • 序言:老撾萬榮一對情侶失蹤糠馆,失蹤者是張志新(化名)和其女友劉穎嘶伟,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體又碌,經(jīng)...
    沈念sama閱讀 45,619評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡九昧,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,819評論 3 336
  • 正文 我和宋清朗相戀三年绊袋,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片铸鹰。...
    茶點故事閱讀 39,932評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡癌别,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出蹋笼,到底是詐尸還是另有隱情展姐,我是刑警寧澤,帶...
    沈念sama閱讀 35,655評論 5 346
  • 正文 年R本政府宣布剖毯,位于F島的核電站圾笨,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏逊谋。R本人自食惡果不足惜擂达,卻給世界環(huán)境...
    茶點故事閱讀 41,265評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望涣狗。 院中可真熱鬧谍婉,春花似錦、人聲如沸镀钓。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,871評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽丁溅。三九已至唤蔗,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間窟赏,已是汗流浹背妓柜。 一陣腳步聲響...
    開封第一講書人閱讀 32,994評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留涯穷,地道東北人棍掐。 一個月前我還...
    沈念sama閱讀 48,095評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像拷况,于是被迫代替她去往敵國和親作煌。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,884評論 2 354

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

  • 從三月份找實習到現(xiàn)在赚瘦,面了一些公司粟誓,掛了不少,但最終還是拿到小米起意、百度鹰服、阿里、京東、新浪悲酷、CVTE套菜、樂視家的研發(fā)崗...
    時芥藍閱讀 42,246評論 11 349
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,129評論 25 707
  • 照他幾許人腸斷笼踩,玉兔銀蟾遠不知。 中秋夜亡嫌,月明如水,萬人仰望掘而,卻不知秋思落進了挟冠,哪家院落。忙了一天袍睡,晚上知染,才給母親...
    涼月牙兒閱讀 3,283評論 1 4
  • 很多人認為嬰兒出生之后如果接觸不止一種語言,開口說話會比只接觸一種語言的孩子晚斑胜。 其實上世紀60年代之前科學界的主...
    Tinko王閱讀 245評論 0 0
  • 不曾記得那時的水秀控淡,只有如今的這些那些。 這是一條小時候走過多遍的路止潘,這是一條殘存至今的河掺炭。 從橋頭開始。我曾在橋...
    山伯閱讀 593評論 2 2