談?wù)凧ava的反射

什么是動態(tài)語言

我們都知道Java是動態(tài)語言符匾,但什么是動態(tài)語言呢祈坠?大致認同的定義是:

程序運行時害碾,允許改變程序結(jié)構(gòu)或變量類型,這種語言稱為動態(tài)語言赦拘。

從這個觀點看慌随,Perl,Python另绩,Ruby是動態(tài)語言儒陨,C++,Java笋籽,C#不是動態(tài)語言蹦漠。


什么是反射

JAVA有著一個非常突出的動態(tài)相關(guān)機制:Reflection(反射)。先看一下反射的概念:

在運行狀態(tài)中车海,對于任意一個類笛园,都能夠知道這個類的所有屬性和方法;對于任意一個對象侍芝,都能夠調(diào)用它的任意方法和屬性研铆;這種動態(tài)獲取信息以及動態(tài)調(diào)用對象方法的功能稱為java語言的反射機制。

換句話說州叠,Java程序可以加載一個運行時才得知名稱的class棵红,獲悉其完整構(gòu)造(但不包括methods定義),并生成其對象實體咧栗、或?qū)ζ鋐ields設(shè)值逆甜、或喚起其methods。


反射機制能做什么

  • 在運行時判斷任意一個對象所屬的類致板;
  • 在運行時構(gòu)造任意一個類的對象交煞;
  • 在運行時判斷任意一個類所具有的成員變量和方法
  • 在運行時調(diào)用任意一個對象的方法斟或;
  • 生成動態(tài)代理素征。

Class

Class 類繼承自O(shè)bject,其實體用以表達Java程序運行時的classes和interfaces,也用來表達enum御毅、array根欧、primitive Java types(boolean, byte, char, short, int, long, float, double)以及關(guān)鍵詞void。

當(dāng)一個class被加載端蛆,或當(dāng)加載器(class loader)的defineClass()被JVM調(diào)用咽块,JVM 便自動產(chǎn)生一個Class 對象。

Class是Reflection故事起源欺税。針對任何您想探勘的類,唯有先為它產(chǎn)生一個Class 對象揭璃,接下來才能經(jīng)由后者喚起為數(shù)十多個的Reflection APIs晚凿。


獲取Class三種方式

1. Object類中的getClass()
Date date = new Date();
Class c = date.getClass();
2. static method-Class.forName()
Class c = Class.forName("java.util.Date");
3. T.class
Class c = Date.class;

創(chuàng)建對象的五種方式

1. 使用new(最常用)
Date d = new Date();
2. 使用Class類的newInstance方法

newInstance方法調(diào)用無參的構(gòu)造函數(shù)創(chuàng)建對象

Date d =  Date.class.newInstance();
3. 使用Constructor類的newInstance方法

java.lang.reflect.Constructor類里也有一個newInstance方法可以創(chuàng)建對象。
可以通過這個newInstance方法調(diào)用有參數(shù)的和私有的構(gòu)造函數(shù)瘦馍。

Constructor<Date> constructor= Date.class.getConstructor();
Date d = constructor.newInstance();
4. 使用clone

用clone方法創(chuàng)建對象并不會調(diào)用任何構(gòu)造函數(shù)歼秽。
要使用clone方法,我們需要先實現(xiàn)Cloneable接口并實現(xiàn)其定義的clone方法情组。

Date d1 = new Date();
Date d2 = (Date)d1.clone();
5. 使用反序列化
ObjectInputStream is = new ObjectInputStream(new FileInputStream("D:/user.obj"));
User userTemp = (User) is.readObject();

Reflection API

Class的方法

1. 獲取Field

Field[] getFields() 獲取所有public域
Field[] getDeclaredFields() 獲取所有域

Class c = Class.forName("java.util.Date");
Field[] fields0 = c.getFields();
Field[] fields1 = c.getDeclaredFields();

Field getField(String name) 獲取指定名稱的域
Field getDeclaredField(String name) 獲取指定名稱的域

Field的方法

Object get(Object obj) 返回obj對象中用Field對象表示的域值
void set(Object obj,Object newValue) 設(shè)置Obj對象中Field對象表示的域的值

User user = new User("001","winson","w5566");
Class c = user.getClass();
Field[] fields =  c.getDeclaredFields();
for (Field field: fields) {
    field.setAccessible(true);
    Object object = field.get(user); //獲取user對象中Field對象表示的域的對象
    System.out.println(object.toString());
    field.set(user,new String("test")); //設(shè)置user對象中Field對象表示的域的值
}
System.out.println(user);

2. 獲取Method

Method[] getMethods() 獲取所有public方法
Method[] getDeclaredMethods() 獲取所有域

Class c = Class.forName("java.util.Date");
Method[] methods0 = c.getMethods();
Method[] methods1 = c.getDeclaredMethods();

3. 獲取Constructor

Constructor[] getConstructors() 獲取所有public構(gòu)造器
Constructor[] getDeclaredConstructors() 獲取所有構(gòu)造器

Class c = Class.forName("java.util.Date");
Constructor[] constructors0 = c.getConstructors();
Constructor[] constructors1 = c.getDeclaredConstructors();

Field燥筷、Method、Constructor的通用的方法

1. 獲取Class對象

Class getDeclaringClass()

2.獲取方法或構(gòu)造器拋出的異常類型 (Contructor|Method)

Class[] getExceptionTypes()

3. 返回修飾權(quán)限的整型值,使用MOdifier類可以分析這個返回值

int getModifiers()

4. 返回一個用于描述構(gòu)造器院崇、方法或域名的字符串

String getName()

5. 返回一個用于描述參數(shù)類型的Class對象數(shù)組 (Contructor|Method)

Class[] getParameterTypes()

5. 返回一個用于描述返回類型的的Class對象 (Method)

Class getReturnTypes()


Modifier的方法

image
public class ReflectTestDemo {
    public static void main(String[] args) throws ClassNotFoundException {
        Class c = Class.forName("java.util.Date");
        System.out.println(c.getModifiers());   //輸出1
        System.out.println(Modifier.toString(c.getModifiers()));    //輸出public

        Method[] methods = c.getDeclaredMethods();
        for (Method m: methods) {
            Class aClass= m.getDeclaringClass();
            Class[] exceptionClass = m.getExceptionTypes();     //獲取拋出的異常類型
            System.out.println(Modifier.toString(m.getModifiers()));   //獲取方法的權(quán)限
            String name = m.getName();  //獲取方法名
            Class[] parameterClass = m.getParameterTypes(); //獲取參數(shù)的類型
            Class returnClass = m.getReturnType();  //獲取返回值類型
        }
    }
}

AccessibleObject的方法

1. 為反射對象設(shè)置可訪問標(biāo)志肆氓,flag為true表明屏蔽Java語言的訪問檢查,使私有屬性也可以被查詢或設(shè)置底瓣。

void setAccessible(boolean flag)

2.返回反射對象的可訪問標(biāo)準的值

boolean isAccessible()

3.設(shè)置對象數(shù)組可訪問標(biāo)志的快捷方法

static void setAccessible(AccessibleObject[] array,boolean flag)

Class c0 = Class.forName("java.util.Date");
Field[] fields =  c.getDeclaredFields();
for (Field field: fields) {
    field.setAccessible(true);  //如果不設(shè)置Accessible為true谢揪,則下面代碼會拋出IllegalAccessException異常
    field.set(user,new String("test")); 
}

Method的invoke方法

調(diào)用對象所描述的方法,傳給定參數(shù)捐凭,并返回方法的返回值拨扶。
在使用包裝器傳遞基本類型的值時,基本類型的返回值必須是未包裝的

public Object invoke(Object implicitParameter,Object[] explicitParamenters)

第一個參數(shù)是隱式參數(shù)傳入被獲取方法的對象茁肠,如果是靜態(tài)方法則傳入null

public class MethodDemo {
    public static void main (String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Method method0 = MethodDemo.class.getMethod("square", double.class);
        Method method1 = Math.class.getMethod("sqrt", double.class);
        double d0 = (Double)method0.invoke(null,3.3);   //如果是static第一個參數(shù)可以為null
        double d1 = (Double)method1.invoke(null,4.4);
        System.out.println(d0);
        System.out.println(d1);

        User user = new User("007","Winson","w5566");
        Method method2 = user.getClass().getMethod("getName");
        String name = (String)method2.invoke(user,new Object[0]);   //如果沒有參數(shù)患民,則傳入new Object[0]
        System.out.println(name);
    }
    public static double square(double x){
        return x*x;
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市垦梆,隨后出現(xiàn)的幾起案子匹颤,更是在濱河造成了極大的恐慌,老刑警劉巖奶赔,帶你破解...
    沈念sama閱讀 218,546評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件惋嚎,死亡現(xiàn)場離奇詭異,居然都是意外死亡站刑,警方通過查閱死者的電腦和手機另伍,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人摆尝,你說我怎么就攤上這事温艇。” “怎么了堕汞?”我有些...
    開封第一講書人閱讀 164,911評論 0 354
  • 文/不壞的土叔 我叫張陵勺爱,是天一觀的道長。 經(jīng)常有香客問我讯检,道長琐鲁,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,737評論 1 294
  • 正文 為了忘掉前任人灼,我火速辦了婚禮围段,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘投放。我一直安慰自己奈泪,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,753評論 6 392
  • 文/花漫 我一把揭開白布灸芳。 她就那樣靜靜地躺著涝桅,像睡著了一般。 火紅的嫁衣襯著肌膚如雪烙样。 梳的紋絲不亂的頭發(fā)上冯遂,一...
    開封第一講書人閱讀 51,598評論 1 305
  • 那天,我揣著相機與錄音误阻,去河邊找鬼债蜜。 笑死,一個胖子當(dāng)著我的面吹牛究反,可吹牛的內(nèi)容都是我干的寻定。 我是一名探鬼主播,決...
    沈念sama閱讀 40,338評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼精耐,長吁一口氣:“原來是場噩夢啊……” “哼狼速!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起卦停,我...
    開封第一講書人閱讀 39,249評論 0 276
  • 序言:老撾萬榮一對情侶失蹤向胡,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后惊完,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體僵芹,經(jīng)...
    沈念sama閱讀 45,696評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,888評論 3 336
  • 正文 我和宋清朗相戀三年小槐,在試婚紗的時候發(fā)現(xiàn)自己被綠了拇派。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片荷辕。...
    茶點故事閱讀 40,013評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖件豌,靈堂內(nèi)的尸體忽然破棺而出疮方,到底是詐尸還是另有隱情,我是刑警寧澤茧彤,帶...
    沈念sama閱讀 35,731評論 5 346
  • 正文 年R本政府宣布骡显,位于F島的核電站,受9級特大地震影響曾掂,放射性物質(zhì)發(fā)生泄漏惫谤。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,348評論 3 330
  • 文/蒙蒙 一珠洗、第九天 我趴在偏房一處隱蔽的房頂上張望石挂。 院中可真熱鬧,春花似錦险污、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,929評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至窖式,卻和暖如春蚁飒,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背萝喘。 一陣腳步聲響...
    開封第一講書人閱讀 33,048評論 1 270
  • 我被黑心中介騙來泰國打工淮逻, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人阁簸。 一個月前我還...
    沈念sama閱讀 48,203評論 3 370
  • 正文 我出身青樓爬早,卻偏偏與公主長得像,于是被迫代替她去往敵國和親启妹。 傳聞我的和親對象是個殘疾皇子筛严,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,960評論 2 355

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

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法饶米,內(nèi)部類的語法桨啃,繼承相關(guān)的語法,異常的語法檬输,線程的語...
    子非魚_t_閱讀 31,634評論 18 399
  • 一照瘾、概述 Java反射機制定義 Java反射機制是在運行狀態(tài)中,對于任意一個類丧慈,都能夠知道這個類中的所有屬性和方法...
    CoderZS閱讀 1,639評論 0 26
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理析命,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,657評論 18 139
  • 整體Retrofit內(nèi)容如下: 1碳却、Retrofit解析1之前哨站——理解RESTful 2队秩、Retrofit解析...
    隔壁老李頭閱讀 4,584評論 2 12
  • 今天,我和媽媽看了一個故事昼浦。里面講的是一個熊孩子在飛機上惹怒了一個日本小伙兒馍资,那個小伙兒就對熊孩子的爸爸說...
    娜娜愛林林閱讀 205評論 0 0