java中的反射總結

剛開始學習java的時候真的很難理解反射究竟是個什麼東西java

一些書籍,哪怕是很經典的書籍都解釋的讓人感受懵懵的,或許的確是我太笨程序員

何況,網上說在未來學習框架的時候須要常常應用到反射機制,這樣一來總讓人內心有些不安數組

就方纔偶然又把講解反射的章節和視頻看了一點,以爲能理解一些了安全

如今決定一氣呵成,邊看邊寫,順便把一些主要的內容和操做都記載到這裏框架

我想,對於我這麼一個笨笨的人來講,學習的最好方法也許就是不斷重複學習

遇到不懂的知識就停下來把以往的從新學一遍,雖然浪費了不少時間,但對我也有些效果this

 

個人理解是:所謂反射,就是根據一個已經實例化了的對象來還原類的完整信息編碼

至少對我而言,我認爲它帶給個人好處是,讓我從下往上的又瞭解了一遍面向對象spa

x_x 在此又痛恨一邊那些厚部頭們,把個人腦細胞搞死一片設計

 

Class類

若是要完成反射,那麼必須瞭解Class類

實例1:經過對象取得包名和類名

1
2
3
4
5
6
7
8
9
10
11
12
13
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( )
  • 類.Class
  • forName( )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class  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類的無參構造對象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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類的有參構造對象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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類對象的有參構造方法,括號裏面參數的寫法是:類型.class
         Constructor<?> con = c.getConstructor( char []. class );
         //用此構造方法構造一個新的字符串對象,參數爲一個char數組
         s = (String) con.newInstance(ch);
         System.out.println( "構造的字符串:"  + s);
     }
}

咱們仍是使用String類作例,由於String類用的比較多,便於理解

這裏須要注意的是,構造方法須要使用getConstructor( )方法得到

至於參數類型則是:原有類型.class

還有一點,不管是有參仍是無參,這裏所使用的構造方法,本來的類裏面必須對應存在

那麼,如何才能知道原有類裏面的構造方法,普通方法,繼承的父類等詳細信息呢?接着看

 

獲取類的結構

要經過反射獲取類的結構咱們這裏要導入一個新的包java.lang.reflect

實例5:取得類的構造方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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:取得類所實現的接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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:取得父類

1
2
3
4
5
6
7
8
9
10
11
12
13
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:取得類的所有方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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:取得本類的所有屬性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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:獲取本類中屬性的值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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是私有屬性,因此要設置安全檢查爲true
         f2.setAccessible( true );
         int  age = ( int ) f2.get(p);
         System.out.println( "年齡: "  + age);
     }
}

 要注意的是:setAccessible()方法能夠設置是否訪問和修改私有屬性

 

坦白說,java學到如今我還沒發現什麼能亮瞎我鈦金眼的知識在裏邊

每次都是寫一堆繁瑣的語法實現個小玩意兒,否則就是拼命調用API,拼命的拋異常

讓自己顯得不夠緊湊的代碼變得愈發累贅

若是我喜歡一門語言,在我利用它作出東西來以前,它自己的特性必須可以打動我

顯然,java並不讓我快樂,也許不少程序員跟我同樣是被迫使用java的

僅以此來安撫我那顆孤獨編碼的心,下面接着看內容

 

反射的應用

實例11:經過反射修改屬性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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:經過反射調用方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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:經過反射操做數組

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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

 

暫時就寫這麼多,我看的書中還有反射在工廠模式中的應用

無非是用forName()方法替換一下,沒什麼可說的

我是個java初級黑,我恨java那種噁心的語法和設計

這都是爲了Android,爲了打基礎,爲了適應之後的工做

Fuck java……

相關文章
相關標籤/搜索