<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                作者:奮斗的小子 鏈接:https://www.zhihu.com/question/24304289/answer/38218810 來源:知乎 著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。 **【此反射來自于李興華的java se 實戰經典,非做廣告,網上有視頻教程資源和筆記word素材,如果有需要可以留言】** **網上百度出來的word文檔,侵刪** **[魔樂MLDN 13天搞定JAVA 魔樂課堂實戰系列.doc_免費高速下載](https://link.zhihu.com/?target=http%3A//pan.baidu.com/share/link%3Fshareid%3D1689691028%26uk%3D52725210)** **——————————————————第二次更新——————————————————** **更新內容:對齊樣式** **反射之中包含了一個“反”的概念,所以要想解釋反射就必須先從“正”開始解釋,一般而言,當用戶使用一個類的時候,應該先知道這個類,而后通過這個類產生實例化對象,但是“反”指的是通過對象找到類。** ~~~ 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 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 } } ~~~
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看