日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

学习java应该如何理解反射?

發布時間:2025/3/21 编程问答 20 豆豆
生活随笔 收集整理的這篇文章主要介紹了 学习java应该如何理解反射? 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
小子吃飯去?猿類/技術渣/熱愛和妹子有關的話題 163?人贊同

【此反射來自于李興華的java se 實戰經典,非做廣告,網上有視頻教程資源和筆記word素材,如果有需要可以留言】

網上百度出來的word文檔,侵刪

魔樂MLDN 13天搞定JAVA 魔樂課堂實戰系列.doc_免費高速下載

——————————————————第二次更新——————————————————

更新內容:對齊樣式

反射之中包含了一個“反”的概念,所以要想解釋反射就必須先從“正”開始解釋,一般而言,當用戶使用一個類的時候,應該先知道這個類,而后通過這個類產生實例化對象,但是“反”指的是通過對象找到類。


packagecn.mldn.demo; classPerson {} publicclassTestDemo { publicstaticvoidmain(String[] args) throwsException { Person per = newPerson() ; // 正著操作 System.out.println(per.getClass().getName()); // 反著來 } }

以上的代碼使用了一個getClass()方法,而后就可以得到對象所在的“包.類”名稱,這就屬于“反”了,但是在這個“反”的操作之中有一個getClass()就作為發起一切反射操作的開端。

Person的父類是Object類,而上面所使用getClass()方法就是Object類之中所定義的方法。

·取得Class對象:public final Class<?> getClass(),反射之中的所有泛型都定義為?,返回值都是Object。

而這個getClass()方法返回的對象是Class類的對象,所以這個Class就是所有反射操作的源頭。但是在講解其真正使用之前還有一個需要先解釋的問題,既然Class是所有反射操作的源頭,那么這個類肯定是最為重要的,而如果要想取得這個類的實例化對象,Java中定義了三種方式:

方式一:通過Object類的getClass()方法取得,基本不用:

packagecn.mldn.demo; classPerson {} publicclassTestDemo { publicstaticvoidmain(String[] args) throwsException { Person per = newPerson() ; // 正著操作 Class<?> cls = per.getClass() ; // 取得Class對象 System.out.println(cls.getName()); // 反著來 } }

方式二:使用“類.class”取得,在日后學習Hibernate開發的時候使用

packagecn.mldn.demo; classPerson {} publicclassTestDemo { publicstaticvoidmain(String[] args) throwsException { Class<?> cls = Person.class; // 取得Class對象 System.out.println(cls.getName()); // 反著來 } }

方式三:使用Class類內部定義的一個static方法,主要使用

·取得Class類對象:public static Class<?> forName(String className) throws ClassNotFoundException;

packagecn.mldn.demo; classPerson {} publicclassTestDemo { publicstaticvoidmain(String[] args) throwsException { Class<?> cls = Class.forName("cn.mldn.demo.Person") ; // 取得Class對象 System.out.println(cls.getName()); // 反著來 } }

那么現在一個新的問題又來了,取得了Class類的對象有什么用處呢?對于對象的實例化操作之前一直依靠構造方法和關鍵字new完成,可是有了Class類對象之后,現在又提供了另外一種對象的實例化方法:

·通過反射實例化對象:public T newInstance() throws InstantiationException, IllegalAccessException;

范例:通過反射實例化對象

packagecn.mldn.demo; classPerson { @Override publicString toString() { return"Person Class Instance ."; } } publicclassTestDemo { publicstaticvoidmain(String[] args) throwsException { Class<?> cls = Class.forName("cn.mldn.demo.Person") ; // 取得Class對象 Object obj = cls.newInstance() ; // 實例化對象,和使用關鍵字new一樣 Person per = (Person) obj ; // 向下轉型 System.out.println(per); } }

那么現在可以發現,對于對象的實例化操作,除了使用關鍵字new之外又多了一個反射機制操作,而且這個操作要比之前使用的new復雜一些,可是有什么用?

對于程序的開發模式之前一直強調:盡量減少耦合,而減少耦合的最好做法是使用接口,但是就算使用了接口也逃不出關鍵字new,所以實際上new是造成耦合的關鍵元兇。

范例:回顧一下之前所編寫的工廠設計模式

packagecn.mldn.demo; interfaceFruit { publicvoideat() ; } classApple implementsFruit { publicvoideat() { System.out.println("吃蘋果。"); }; } classFactory { publicstaticFruit getInstance(String className) { if("apple".equals(className)){ returnnewApple() ; } returnnull; } } publicclassFactoryDemo { publicstaticvoidmain(String[] args) { Fruit f = Factory.getInstance("apple") ; f.eat() ; } }

以上為之前所編寫最簡單的工廠設計模式,但是在這個工廠設計模式之中有一個最大的問題:如果現在接口的子類增加了,那么工廠類肯定需要修改,這是它所面臨的最大問題,而這個最大問題造成的關鍵性的病因是new,那么如果說現在不使用關鍵字new了,變為了反射機制呢?

反射機制實例化對象的時候實際上只需要“包.類”就可以,于是根據此操作,修改工廠設計模式。

packagecn.mldn.demo; interfaceFruit { publicvoideat() ; } classApple implementsFruit { publicvoideat() { System.out.println("吃蘋果。"); }; } classOrange implementsFruit { publicvoideat() { System.out.println("吃橘子。"); }; } classFactory { publicstaticFruit getInstance(String className) { Fruit f = null; try{ f = (Fruit) Class.forName(className).newInstance() ; } catch(Exception e) { e.printStackTrace(); } returnf ; } } publicclassFactoryDemo { publicstaticvoidmain(String[] args) { Fruit f = Factory.getInstance("cn.mldn.demo.Orange") ; f.eat() ; } }

發現,這個時候即使增加了接口的子類,工廠類照樣可以完成對象的實例化操作,這個才是真正的工廠類,可以應對于所有的變化。如果單獨從開發角度而言,與開發者關系不大,但是對于日后學習的一些框架技術這個就是它實現的命脈,在日后的程序開發上,如果發現操作的過程之中需要傳遞了一個完整的“包.類”名稱的時候幾乎都是反射機制作用。

3.12.2 、反射的深入應用

以上只是利用了Class類作為了反射實例化對象的基本應用,但是對于一個實例化對象而言,它需要調用類之中的構造方法、普通方法、屬性,而這些操作都可以通過反射機制完成。

3.12.2 .1、調用構造

使用反射機制也可以取得類之中的構造方法,這個方法在Class類之中已經明確定義了:

以下兩個方法

取得一個類的全部構造:

public Constructor<?>[] getConstructors() throws SecurityException

取得一個類的指定參數構造:

public Constructor<T> getConstructor(Class<?>... parameterTypes) throws NoSuchMethodException, SecurityException


現在發現以上的兩個方法返回的都是java.lang.reflect.Constructor類的對象。

范例:取得一個類之中的全部構造

packagecn.mldn.demo; importjava.lang.reflect.Constructor; classPerson { // CTRL + K publicPerson() {} publicPerson(String name) {} publicPerson(String name,intage) {} } publicclassTestDemo { publicstaticvoidmain(String[] args) throwsException { Class<?> cls = Class.forName("cn.mldn.demo.Person") ; // 取得Class對象 Constructor<?> cons [] = cls.getConstructors() ; // 取得全部構造 for(intx = 0; x < cons.length; x++) { System.out.println(cons[x]); } } }

驗證:在之前強調的一個簡單Java類必須存在一個無參構造方法

范例:觀察沒有無參構造的情況

packagecn.mldn.demo; classPerson { // CTRL + K privateString name; privateintage; publicPerson(String name,intage) { this.name= name ; this.age= age ; } @Override publicString toString() { return"Person [name="+ name+ ", age="+ age+ "]"; } } publicclassTestDemo { publicstaticvoidmain(String[] args) throwsException { Class<?> cls = Class.forName("cn.mldn.demo.Person") ; // 取得Class對象 Object obj = cls.newInstance(); // 實例化對象 System.out.println(obj); } }

此時程序運行的時候出現了錯誤提示“java.lang.InstantiationException”,因為以上的方式使用反射實例化對象時需要的是類之中要提供無參構造方法,但是現在既然沒有了無參構造方法,那么就必須明確的找到一個構造方法,而后利用Constructor類之中的新方法實例化對象:

·實例化對象:public T newInstance(Object... initargs) throws InstantiationException, IllegalAccessException,IllegalArgumentException, InvocationTargetException

packagecn.mldn.demo; importjava.lang.reflect.Constructor; classPerson { // CTRL + K privateString name; privateintage; publicPerson(String name,intage) { this.name= name ; this.age= age ; } @Override publicString toString() { return"Person [name="+ name+ ", age="+ age+ "]"; } } publicclassTestDemo { publicstaticvoidmain(String[] args) throwsException { Class<?> cls = Class.forName("cn.mldn.demo.Person") ; // 取得Class對象 // 取得指定參數類型的構造方法 Constructor<?> cons = cls.getConstructor(String.class,int.class) ; Object obj = cons.newInstance("張三", 20); // 為構造方法傳遞參數 System.out.println(obj); } }

很明顯,調用無參構造方法實例化對象要比調用有參構造的更加簡單、方便,所以在日后的所有開發之中,凡是有簡單Java類出現的地方,都一定要提供無參構造。

3.12.2 .2、調用普通方法

當取得了一個類實例化對象之后,下面最需要調用的肯定是類之中的方法,所以可以繼續使用Class類取得一個類中所定義的方法定義:

·取得全部方法:public Method[] getMethods() throws SecurityException;

·取得指定方法:public Method getMethod(String name, Class<?>... parameterTypes) throws?NoSuchMethodException, SecurityException

發現以上的方法返回的都是java.lang.reflect.Method類的對象。

范例:取得一個類之中所定義的全部方法

packagecn.mldn.demo; importjava.lang.reflect.Method; classPerson { privateString name; publicvoidsetName(String name) { this.name= name; } publicString getName() { returnname; } } publicclassTestDemo { publicstaticvoidmain(String[] args) throwsException { Class<?> cls = Class.forName("cn.mldn.demo.Person") ; // 取得Class對象 Method met [] = cls.getMethods() ; // 取得全部方法 for(intx = 0; x < met.length; x++) { System.out.println(met[x]); } } }

但是取得了Method類對象最大的作用不再于方法的列出(方法的列出都在開發工具上使用了),但是對于取得了Method類對象之后還有一個最大的功能,就是可以利用反射調用類中的方法:

·調用方法:public Object invoke(Object obj, Object... args) throws IllegalAccessException,IllegalArgumentException, InvocationTargetException

之前調用類中方法的時候使用的都是“對象.方法”,但是現在有了反射之后,可以直接利用Object類調用指定子類的操作方法。(同時解釋一下,為什么setter、getter方法的命名要求如此嚴格)。

范例:利用反射調用Person類之中的setName()、getName()方法

packagecn.mldn.demo; importjava.lang.reflect.Method; classPerson { privateString name; publicvoidsetName(String name) { this.name= name; } publicString getName() { returnname; } } publicclassTestDemo { publicstaticvoidmain(String[] args) throwsException { Class<?> cls = Class.forName("cn.mldn.demo.Person") ; // 取得Class對象 Object obj = cls.newInstance(); // 實例化對象,沒有向Person轉型 String attribute = "name"; // 要調用類之中的屬性 Method setMet = cls.getMethod("set"+ initcap(attribute), String.class);// setName() Method getMet = cls.getMethod("get"+ initcap(attribute));// getName() setMet.invoke(obj, "張三") ; // 等價于:Person對象.setName("張三") System.out.println(getMet.invoke(obj));// 等價于:Person對象.getName() } publicstaticString initcap(String str) { returnstr.substring(0,1).toUpperCase().concat(str.substring(1)) ; } }

在日后的所有框架技術開發之中,簡單Java類都是如此應用的,所以必須按照標準進行。

3.12.2 .3、調用成員

類之中最后一個組成部分就是成員(Field,也可以稱為屬性),如果要通過反射取得類的成員可以使用方法如下:

·取得本類的全部成員:public Field[] getDeclaredFields() throws SecurityException;

·取得指定的成員:public Field getDeclaredField(String name) throws NoSuchFieldException, SecurityException;

這兩個方法的返回值類型是java.lang.reflect.Field類的對象,下面首先觀察如何取得一個類之中的全部屬性。

范例:取得一個類之中的全部屬性

packagecn.mldn.demo; importjava.lang.reflect.Field; classPerson { privateString name; } publicclassTestDemo { publicstaticvoidmain(String[] args) throwsException { Class<?> cls = Class.forName("cn.mldn.demo.Person") ; // 取得Class對象 Field field [] = cls.getDeclaredFields() ; // 取得全部屬性 for(intx = 0; x < field.length; x++) { System.out.println(field[x]); } } }

但是找到Field實際上就找到了一個很有意思的操作,在Field類之中提供了兩個方法:

·設置屬性內容(類似于:對象.屬性=?內容):public void set(Object obj, Object value)

throws IllegalArgumentException, IllegalAccessException;

·取得屬性內容(類似于:對象.屬性):public Object get(Object obj)

throws IllegalArgumentException, IllegalAccessException

可是從類的開發要求而言,一直都強調類之中的屬性必須封裝,所以現在調用之前要想辦法解除封裝。

·解除封裝:public void setAccessible(boolean flag) throws SecurityException;

范例:利用反射操作類中的屬性

packagecn.mldn.demo; importjava.lang.reflect.Field; classPerson { privateString name; } publicclassTestDemo { publicstaticvoidmain(String[] args) throwsException { Class<?> cls = Class.forName("cn.mldn.demo.Person"); // 取得Class對象 Object obj = cls.newInstance(); // 對象實例化屬性才會分配空間 Field nameField = cls.getDeclaredField("name") ; // 找到name屬性 nameField.setAccessible(true) ; // 解除封裝了 nameField.set(obj, "張三") ; // Person對象.name = "張三" System.out.println(nameField.get(obj)); // Person對象.name } } 編輯于 2015-12-13?24 條評論?感謝? 分享 ?收藏???沒有幫助???舉報???作者保留權利 郭無心?做好自己 30?人贊同

反射機制:所謂的反射機制就是java語言在運行時擁有一項自觀的能力。通過這種能力可以徹底的了解自身的情況為下一步的動作做準備。

下面具體介紹一下java的反射機制。


Java的反射機制的實現要借助于4個類:class,Constructor,Field,Method;

其中class代表的時類對 象,Constructor-類的構造器對象,Field-類的屬性對象,Method-類的方法對象。通過這四個對象我們可以粗略的看到一個類的各個組 成部分。


Java反射的作用:

在Java運行時環境中,對于任意一個類,可以知道這個類有哪些屬性和方法。對于任意一個對象,可以調用它的任意一個方法。這種動態獲取類的信息以及動態調用對象的方法的功能來自于Java 語言的反射(Reflection)機制。


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

在運行時判斷任意一個對象所屬的類。 在運行時構造任意一個類的對象。 在運行時判斷任意一個類所具有的成員變量和方法。 在運行時調用任意一個對象的方法

反射的常用類和函數:Java反射機制的實現要借助于4個類:Class,Constructor,Field,Method;


其中class代表的是類對象,Constructor-類的構造器對象,Field-類的屬性對象,Method-類的方法對象,通過這四個對象我們可以粗略的看到一個類的各個組成部分。其中最核心的就是Class類,它是實現反射的基礎,它包含的方法我們在第一部分已經進行了基本的闡述。應用反射時我們最關心的一般是一個類的構造器、屬性和方法,下面我們主要介紹Class類中針對這三個元素的方法:


1、得到構造器的方法

Constructor getConstructor(Class[] params) -- 獲得使用特殊的參數類型的公共構造函數, Constructor[] getConstructors() -- 獲得類的所有公共構造函數 Constructor getDeclaredConstructor(Class[] params) -- 獲得使用特定參數類型的構造函數(與接入級別無關) Constructor[] getDeclaredConstructors() -- 獲得類的所有構造函數(與接入級別無關)

2、獲得字段信息的方法

Field getField(String name) -- 獲得命名的公共字段 Field[] getFields() -- 獲得類的所有公共字段 Field getDeclaredField(String name) -- 獲得類聲明的命名的字段 Field[] getDeclaredFields() -- 獲得類聲明的所有字段

3、獲得方法信息的方法

Method getMethod(String name, Class[] params) -- 使用特定的參數類型,獲得命名的公共方法 Method[] getMethods() -- 獲得類的所有公共方法 Method getDeclaredMethod(String name, Class[] params) -- 使用特寫的參數類型,獲得類聲明的命名的方法 Method[] getDeclaredMethods() -- 獲得類聲明的所有方法

在程序開發中使用反射并結合屬性文件,可以達到程序代碼與配置文件相分離的目的

如果我們想要得到對象的信息,一般需要“引入需要的‘包.類’的名稱——通過new實例化——取得實例化對象”這樣的過程。使用反射就可以變成“實例化對象——getClass()方法——得到完整的‘包.類’名稱”這樣的過程。

正常方法是通過一個類創建對象,反射方法就是通過一個對象找到一個類的信息。


from:?https://www.zhihu.com/question/24304289

總結

以上是生活随笔為你收集整理的学习java应该如何理解反射?的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。