3C科技 娛樂遊戲 美食旅遊 時尚美妝 親子育兒 生活休閒 金融理財 健康運動 寰宇綜合

Zi 字媒體

2017-07-25T20:27:27+00:00
加入好友
剛開始學習Java的時候真的很難理解反射到底是個什麼東西一些書籍,哪怕是很經典的書籍都解釋的讓人感覺懵懵的,或許的確是我太笨況且,網上說在將來學習框架的時候需要經常應用到反射機制,這樣一來總讓人心裡有些不安就方才偶然又把講解反射的章節和視頻看了一點,覺得能理解一些了現在決定一鼓作氣,邊看邊寫,順便把一些主要的內容和操作都記載到這裡我想,對於我這麼一個笨笨的人來說,學習的最好方法也許就是不斷重複遇到不懂的知識就停下來把以往的重新學一遍,雖然浪費了很多時間,但對我也有些效果我的理解是:所謂反射,就是根據一個已經實例化了的對象來還原類的完整信息至少對我而言,我認為它帶給我的好處是,讓我從下往上的又了解了一遍面向對象x_x 在此又痛恨一邊那些厚部頭們,把我的腦細胞搞死一片Class類如果要完成反射,那麼必須了解Class類實例1:通過對象取得包名和類名package org.siu;class Test {}public class Demo {public static void main(String args) {Test t = new Test;System.out.println(t.getClass);System.out.println(t.getClass.getName);}}編譯結果如下,注意包的編譯方式即可此處的getClass方法是默認繼承自Object類的在java中,Object類是所有類的父類,同樣,所有類的實例化對象也都是Class類的實例因此,這樣一來就會牽扯到向上轉型和向下轉型的概念由於向下轉型的不安全因素,在這裡泛型也會接踵而來(不過我想說的是,此處的泛型設計很刺眼!尼瑪,整個java的語法設計同樣刺眼,超噁心!!!)實例2:Class類的實例化由於Class類沒有構造方法,所以實例化Class類的方式有點特殊,有三種方式:對象.getClass類.ClassforNameclass Test {}public class Demo {public static void main(String args) {//方式一:Test t = new Test;Class<? extends Test> c1 = t.getClass;System.out.println(c1);//方式二://為了避免特殊性,這裡不用Test類,而用java庫中的String類Class<String> c2 = String.class;System.out.println(c2);//方式三://forName方法會拋出異常Class<?> c3 = null;try {c3 = Class.forName("Test");} catch (ClassNotFoundException e) {e.printStackTrace;}System.out.println(c3);}}其中,forName方法需要重點掌握,因為它可以在類不確定的情況下實例化Class,更具靈活性Class類的應用Class類中有一個方法叫做newInstance,它可以用來創建一個Class類對象的新實例怎麼說呢?Class對象包含的內容就是反射好的那個類,我們要構造那個類的新實例(新對象)實例3:Class類的無參構造對象public class Demo {public static void main(String args) {//實例化Class對象,forName方法會拋異常Class<?> c = null;try {//這裡需要完整的包名和類名c = Class.forName("java.lang.String");} catch (ClassNotFoundException e) {e.printStackTrace;}//生成一個字元串的引用String s = null;try {//將構造好的對象向下轉型為String類//newInstance方法會拋異常s = (String) c.newInstance;} catch (InstantiationException e) {e.printStackTrace;} catch (IllegalAccessException e) {e.printStackTrace;}System.out.println("字元串長度: " + s.length);}}這樣就通過無參數的形式構造了一個新的對象,如同正常模式中通過無參構造方法來構造新對象一樣我們知道,類中除了有無參構造方法,還會存在有參數的構造方法那在反射中如何通過有參數的形式構造對象呢?接著看實例4:Class類的有參構造對象import java.lang.reflect.Constructor;public class Demo {//下面的幾個方法拋出來的異常太多,為了代碼的緊湊性,這裡就直接拋給虛擬機了public static void main(String args) throws Exception {Class<?> c = null;try {c = Class.forName("java.lang.String");} catch (ClassNotFoundException e) {e.printStackTrace;}char ch = {'h','e','l','l','o'};String s = null;//獲得Class類對象的有參構造方法,括弧裡面參數的寫法是:類型.classConstructor<?> con = c.getConstructor(char.class);//用此構造方法構造一個新的字元串對象,參數為一個char數組s = (String) con.newInstance(ch);System.out.println("構造的字元串:" + s);}}我們還是使用String類做例,因為String類用的比較多,便於理解這裡需要注意的是,構造方法需要使用getConstructor方法獲得至於參數類型則是:原有類型.class還有一點,無論是有參還是無參,這裡所使用的構造方法,原本的類裡面必須對應存在那麼,如何才能知道原有類裡面的構造方法,普通方法,繼承的父類等詳細信息呢?接著看獲取類的結構要通過反射獲取類的結構我們這裡要導入一個新的包java.lang.reflect實例5:取得類的構造方法import java.lang.reflect.Constructor;import java.util.Arrays;public class Demo {//下面的幾個方法拋出來的異常太多,為了代碼的緊湊性,這裡就直接拋給虛擬機了public static void main(String args) throws Exception {Class<?> c = null;try {c = Class.forName("java.lang.Boolean");} catch (ClassNotFoundException e) {e.printStackTrace;}//這裡的getConstructors方法返回的是一個Constructor數組Constructor<?> cons = c.getConstructors;//列印的方式你可以自己寫,為了方便我用Arrays.toString,湊合著看System.out.println(Arrays.toString(cons));}}我選擇了Boolean類來做例,因為Boolean類的構造方法就兩個,方便看實例6:取得類所實現的介面import java.util.Arrays;public class Demo {public static void main(String args) throws Exception {Class<?> c = null;try {c = Class.forName("java.lang.Boolean");} catch (ClassNotFoundException e) {e.printStackTrace;}Class<?> in = c.getInterfaces;System.out.println(Arrays.toString(in));}}沒什麼好說的,看結果實例7:取得父類public class Demo {public static void main(String args) throws Exception {Class<?> c = null;try {c = Class.forName("java.lang.Boolean");} catch (ClassNotFoundException e) {e.printStackTrace;}//注意了,這裡不會是數組,why?Class<?> su = c.getSuperclass;System.out.println(su);}}別忘了,java中是單繼承,父類只有一個實例8:取得類的全部方法import java.lang.reflect.Method;public class Demo {public static void main(String args) throws Exception {Class<?> c = null;try {c = Class.forName("java.lang.Boolean");} catch (ClassNotFoundException e) {e.printStackTrace;}Method m = c.getMethods;//好吧,這次我就大發慈悲的寫個列印列表出來for (int i = 0; i < m.length; i++) {System.out.println(m[i]);}}}截取一部分,看看,意思下就行了……這幾個例子都比較簡單實例9:取得本類的全部屬性import java.lang.reflect.Field;class Person {private String name;private int age;}public class Demo {public static void main(String args) throws Exception {Class<?> c = null;try {c = Class.forName("Person");} catch (ClassNotFoundException e) {e.printStackTrace;}Field f = c.getDeclaredFields;for (int i = 0; i < f.length; i++) {System.out.println(f[i]);}}}getDeclaredFielsd方法可以獲取全部屬性,getFields只能獲取公共屬性實例10:獲取本類中屬性的值import java.lang.reflect.Field;class Person {public String name;private int age;public Person(String name, int age) {this.name = name;this.age = age;}}public class Demo {public static void main(String args) throws Exception {Person p = new Person("zhangsan",12);Class<?> c = p.getClass;//獲取公共屬性的值Field f1 = c.getField("name");//get(p)表明要獲取是哪個對象的值String str = (String) f1.get(p);System.out.println("姓名: " + str);//獲取私有屬性的值Field f2 = c.getDeclaredField("age");//age是私有屬性,所以要設置安全檢查為truef2.setAccessible(true);int age = (int) f2.get(p);System.out.println("年齡: " + age);}}要注意的是:setAccessible方法可以設置是否訪問和修改私有屬性坦白說,java學到現在我還沒發現什麼能亮瞎我鈦金眼的知識在裡邊每次都是寫一堆繁瑣的語法實現個小玩意兒,不然就是拚命調用API,拚命的拋異常讓本身顯得不夠緊湊的代碼變得愈發累贅如果我喜歡一門語言,在我利用它做出東西來之前,它本身的特性必須能夠打動我顯然,java並不讓我快樂,也許很多程序員跟我一樣是被迫使用java的僅以此來安撫我那顆孤獨編碼的心,下面接著看內容反射的應用實例11:通過反射修改屬性import java.lang.reflect.Field;class Person {private String name;public Person(String name) {this.name = name;}public String toString {return "姓名: " + this.name;}}public class Demo {public static void main(String args) throws Exception {Person p = new Person("王二狗");System.out.println(p);Class<?> c = p.getClass;//定義要修改的屬性Field f = c.getDeclaredField("name");f.setAccessible(true);//修改屬性,傳入要設置的對象和值f.set(p, "張二蛋");System.out.println(p);}}幾個方法都是有聯繫的,如果看不懂就先熟悉上面幾個例子實例12:通過反射調用方法import java.lang.reflect.Method;class Person {public void print(int i) {System.out.println("我在寫數字: " + i);}public static void say(String str) {System.out.println("我在說: " + str);}}public class Demo {public static void main(String args) throws Exception {Person p = new Person;Class<?> c = p.getClass;//getMethod方法需要傳入方法名,和參數類型Method m1 = c.getMethod("print", int.class);//invoke表示調用的意思,需要傳入對象和參數m1.invoke(p, 10);Method m2 = c.getMethod("say", String.class);//這裡的null表示不由對象調用,也就是靜態方法m2.invoke(null, "你妹");}}這裡演示了一個普通的有參方法和一個靜態方法既然有參數的都寫出來了,那麼無參的就更簡單了,直接傳入一個對象即可實例13:通過反射操作數組import java.lang.reflect.Array;public class Demo {public static void main(String args) throws Exception {int arr = {1,2,3,4,5};Class<?> c = arr.getClass.getComponentType;System.out.println("數組類型: " + c.getName);int len = Array.getLength(arr);System.out.println("數組長度: " + len);System.out.print("遍曆數組: ");for (int i = 0; i < len; i++) {System.out.print(Array.get(arr, i) + " ");}System.out.println;//修改數組System.out.println("修改前的第一個元素: " + Array.get(arr, 0));Array.set(arr, 0, 3);System.out.println("修改後的第一個元素: " + Array.get(arr, 0));}}這裡要注意一點,getComponentType返回的是數組元素的Class

本文由yidianzixun提供 原文連結

寫了 5860316篇文章,獲得 23313次喜歡
精彩推薦