Java反射機制及IoC原理

一. 反射機制概念

  主要是指程序能夠訪問,檢測和修改它自己狀態或行爲的一種能力,並能根據自身行爲的狀態和結果,調整或修改應用所描述行爲的狀態和相關的語義。在java中,只要給定類的名字, 那麼就能夠經過反射機制來得到類的全部信息。html

  反射是Java中一種強大的工具,可以使咱們很方便的建立靈活的代碼,這些代碼能夠再運行時裝配,無需在組件之間進行源代碼連接。可是反射使用不當會成本很高!java

  類中有什麼信息,利用反射機制就能能夠得到什麼信息,不過前提是得知道類的名字。c++

二. 反射機制的做用

  1. 在運行時判斷任意一個對象所屬的類;
  2. 在運行時獲取類的對象;
  3. 在運行時訪問java對象的屬性,方法,構造方法等。

三. 反射機制的優勢與缺點

首先要搞清楚爲何要用反射機制?直接建立對象不就能夠了嗎,這就涉及到了動態與靜態的概念。 
靜態編譯:在編譯時肯定類型,綁定對象,即經過。
動態編譯:運行時肯定類型,綁定對象。動態編譯最大限度發揮了java的靈活性,體現了多態的應用,有以下降類之間的藕合性。 數組

反射機制的優勢:能夠實現動態建立對象和編譯,體現出很大的靈活性(特別是在J2EE的開發中它的靈活性就表現的十分明顯)。經過反射機制咱們能夠得到類的各類內容,進行了反編譯。對於JAVA這種先編譯再運行的語言來講,反射機制可使代碼更加靈活,更加容易實現面向對象。app

  好比,一個大型的軟件,不可能一次就把把它設計的很完美,當這個程序編譯後,發佈了,當發現須要更新某些功能時,咱們不可能要用戶把之前的卸載,再從新安裝新的版本,假如這樣的話,這個軟件確定是沒有多少人用的。採用靜態的話,須要把整個程序從新編譯一次才能夠實現功能的更新,而採用反射機制的話,它就能夠不用卸載,只須要在運行時才動態的建立和編譯,就能夠實現該功能。 框架

反射機制的缺點:對性能有影響。使用反射基本上是一種解釋操做,咱們能夠告訴JVM,咱們但願作什麼而且它 知足咱們的要求。這類操做老是慢於只直接執行相同的操做。ide

四. 反射機制的示例

1.經過一個對象得到完整的包名和類名

添加一句:全部類的對象其實都是Class的實例。函數

 1 package Reflect;
 2 
 3 class Demo{
 4     //other codes...
 5 }
 6 
 7 class hello{
 8     public static void main(String[] args) {
 9         Demo demo=new Demo();
10         System.out.println(demo.getClass().getName());
11     }
12 }
13 //【運行結果】:Reflect.Demo

2.實例化Class類對象

 1 package Reflect;
 2 
 3 class Demo{
 4     //other codes...
 5 }
 6 
 7 class hello{
 8     public static void main(String[] args) {
 9         Class<?> demo1=null;
10         Class<?> demo2=null;
11         Class<?> demo3=null;
12         try{
13             //通常儘可能採用這種形式
14             demo1=Class.forName("Reflect.Demo");
15         }catch(Exception e){
16             e.printStackTrace();
17         }
18         demo2=new Demo().getClass();
19         demo3=Demo.class;
20 
21         System.out.println("類名稱   "+demo1.getName());
22         System.out.println("類名稱   "+demo2.getName());
23         System.out.println("類名稱   "+demo3.getName());
24     }
25 }
26 //【運行結果】:
27 //類名稱   Reflect.Demo
28 //類名稱   Reflect.Demo
29 //類名稱   Reflect.Demo

3.經過Class實例化其餘類的對象

 1 package Reflect;
 2 
 3 class Person{
 4     public String getName() {
 5         return name;
 6     }
 7     public void setName(String name) {
 8         this.name = name;
 9     }
10     public int getAge() {
11         return age;
12     }
13     public void setAge(int age) {
14         this.age = age;
15     }
16     @Override
17     public String toString(){
18         return "["+this.name+"  "+this.age+"]";
19     }
20     private String name;
21     private int age;
22 }
23 
24 class hello{
25     public static void main(String[] args) {
26         Class<?> demo=null;
27         try{
28             demo=Class.forName("Reflect.Person");
29         }catch (Exception e) {
30             e.printStackTrace();
31         }
32         Person per=null;
33         try {
34             per=(Person)demo.newInstance();
35         } catch (InstantiationException e) {
36             // TODO Auto-generated catch block
37             e.printStackTrace();
38         } catch (IllegalAccessException e) {
39             // TODO Auto-generated catch block
40             e.printStackTrace();
41         }
42         per.setName("Rollen");
43         per.setAge(20);
44         System.out.println(per);
45     }
46 }
47 //【運行結果】:
48 //[Rollen  20]

可是注意一下,當咱們把Person中的默認的無參構造函數取消的時候,好比本身定義只定義一個有參數的構造函數以後,會出現錯誤:工具

好比定義了一個構造函數:性能

1 public Person(String name, int age) {
2         this.age=age;
3         this.name=name;
4     }

而後繼續運行上面的程序,會出現:

java.lang.InstantiationException: Reflect.Person
at java.lang.Class.newInstance0(Class.java:340)
at java.lang.Class.newInstance(Class.java:308)
at Reflect.hello.main(hello.java:39)
Exception in thread "main" java.lang.NullPointerException
at Reflect.hello.main(hello.java:47)

因此你們之後再編寫使用Class實例化其餘類的對象的時候,必定要本身定義無參的構造函數。

4.經過Class調用其餘類中的構造函數 (也能夠經過這種方式經過Class建立其餘類的對象)

 1 package Reflect;
 2 
 3 import java.lang.reflect.Constructor;
 4 
 5 class Person{
 6     public Person() {   
 7 
 8     }
 9     public Person(String name){
10         this.name=name;
11     }
12     public Person(int age){
13         this.age=age;
14     }
15     public Person(String name, int age) {
16         this.age=age;
17         this.name=name;
18     }
19     public String getName() {
20         return name;
21     }
22     public int getAge() {
23         return age;
24     }
25     @Override
26     public String toString(){
27         return "["+this.name+"  "+this.age+"]";
28     }
29     private String name;
30     private int age;
31 }
32 
33 class hello{
34     public static void main(String[] args) {
35         Class<?> demo=null;
36         try{
37             demo=Class.forName("Reflect.Person");
38         }catch (Exception e) {
39             e.printStackTrace();
40         }
41         Person per1=null;
42         Person per2=null;
43         Person per3=null;
44         Person per4=null;
45         //取得所有的構造函數
46         Constructor<?> cons[]=demo.getConstructors();
47         try{
48             per1=(Person)cons[0].newInstance();
49             per2=(Person)cons[1].newInstance("Rollen");
50             per3=(Person)cons[2].newInstance(20);
51             per4=(Person)cons[3].newInstance("Rollen",20);
52         }catch(Exception e){
53             e.printStackTrace();
54         }
55         System.out.println(per1);
56         System.out.println(per2);
57         System.out.println(per3);
58         System.out.println(per4);
59     }
60 }
61 //【運行結果】:
62 //[null  0]
63 //[Rollen  0]
64 //[null  20]
65 //[Rollen  20]
View Code

5.返回一個類實現的接口

 1 package Reflect;
 2 
 3 interface China{
 4     public static final String name="Rollen";
 5     public static  int age=20;
 6     public void sayChina();
 7     public void sayHello(String name, int age);
 8 }
 9 
10 class Person implements China{
11     public Person() {
12 
13     }
14     public Person(String sex){
15         this.sex=sex;
16     }
17     public String getSex() {
18         return sex;
19     }
20     public void setSex(String sex) {
21         this.sex = sex;
22     }
23     @Override
24     public void sayChina(){
25         System.out.println("hello ,china");
26     }
27     @Override
28     public void sayHello(String name, int age){
29         System.out.println(name+"  "+age);
30     }
31     private String sex;
32 }
33 
34 class hello{
35     public static void main(String[] args) {
36         Class<?> demo=null;
37         try{
38             demo=Class.forName("Reflect.Person");
39         }catch (Exception e) {
40             e.printStackTrace();
41         }
42         //保存全部的接口
43         Class<?> intes[]=demo.getInterfaces();
44         for (int i = 0; i < intes.length; i++) {
45             System.out.println("實現的接口   "+intes[i].getName());
46         }
47     }
48 }
49 //【運行結果】:
50 //實現的接口   Reflect.China
View Code

(如下幾個例子,都會用到這個例子的Person類,因此爲節省篇幅,此處再也不粘貼Person的代碼部分,只粘貼主類hello的代碼)

6.取得其餘類中的父類

 1 class hello{
 2     public static void main(String[] args) {
 3         Class<?> demo=null;
 4         try{
 5             demo=Class.forName("Reflect.Person");
 6         }catch (Exception e) {
 7             e.printStackTrace();
 8         }
 9         //取得父類
10         Class<?> temp=demo.getSuperclass();
11         System.out.println("繼承的父類爲:   "+temp.getName());
12     }
13 }
14 //【運行結果】
15 //繼承的父類爲:   java.lang.Object
View Code

7.得到其餘類中的所有構造函數

 1 //這個例子須要在程序開頭添加import java.lang.reflect.*;
 2 class hello{
 3     public static void main(String[] args) {
 4         Class<?> demo=null;
 5         try{
 6             demo=Class.forName("Reflect.Person");
 7         }catch (Exception e) {
 8             e.printStackTrace();
 9         }
10         Constructor<?>cons[]=demo.getConstructors();
11         for (int i = 0; i < cons.length; i++) {
12             System.out.println("構造方法:  "+cons[i]);
13         }
14     }
15 }
16 //【運行結果】:
17 //構造方法:  public Reflect.Person()
18 //構造方法:  public Reflect.Person(java.lang.String)
View Code
 1 class hello{
 2     public static void main(String[] args) {
 3         Class<?> demo=null;
 4         try{
 5             demo=Class.forName("Reflect.Person");
 6         }catch (Exception e) {
 7             e.printStackTrace();
 8         }
 9         Constructor<?>cons[]=demo.getConstructors();
10         for (int i = 0; i < cons.length; i++) {
11             Class<?> p[]=cons[i].getParameterTypes();
12             System.out.print("構造方法:  ");
13             int mo=cons[i].getModifiers();
14             System.out.print(Modifier.toString(mo)+" ");
15             System.out.print(cons[i].getName());
16             System.out.print("(");
17             for(int j=0;j<p.length;++j){
18                 System.out.print(p[j].getName()+" arg"+i);
19                 if(j<p.length-1){
20                     System.out.print(",");
21                 }
22             }
23             System.out.println("){}");
24         }
25     }
26 }
27 //【運行結果】:
28 //構造方法:  public Reflect.Person(){}
29 //構造方法:  public Reflect.Person(java.lang.String arg1){}
View Code

8.取得其餘類的所有屬性,將這些整理在一塊兒,也就是經過class取得一個類的所有框架

 1 class hello {
 2     public static void main(String[] args) {
 3         Class<?> demo = null;
 4         try {
 5             demo = Class.forName("Reflect.Person");
 6         } catch (Exception e) {
 7             e.printStackTrace();
 8         }
 9         System.out.println("===============本類屬性========================");
10         // 取得本類的所有屬性
11         Field[] field = demo.getDeclaredFields();
12         for (int i = 0; i < field.length; i++) {
13             // 權限修飾符
14             int mo = field[i].getModifiers();
15             String priv = Modifier.toString(mo);
16             // 屬性類型
17             Class<?> type = field[i].getType();
18             System.out.println(priv + " " + type.getName() + " "
19                     + field[i].getName() + ";");
20         }
21         System.out.println("===============實現的接口或者父類的屬性========================");
22         // 取得實現的接口或者父類的屬性
23         Field[] filed1 = demo.getFields();
24         for (int j = 0; j < filed1.length; j++) {
25             // 權限修飾符
26             int mo = filed1[j].getModifiers();
27             String priv = Modifier.toString(mo);
28             // 屬性類型
29             Class<?> type = filed1[j].getType();
30             System.out.println(priv + " " + type.getName() + " "
31                     + filed1[j].getName() + ";");
32         }
33     }
34 }
35 //【運行結果】:
36 //===============本類屬性========================
37 //private java.lang.String sex;
38 //===============實現的接口或者父類的屬性========================
39 //public static final java.lang.String name;
40 //public static final int age;
View Code

9.經過反射調用其餘類中的方法

 1 class hello {
 2     public static void main(String[] args) {
 3         Class<?> demo = null;
 4         try {
 5             demo = Class.forName("Reflect.Person");
 6         } catch (Exception e) {
 7             e.printStackTrace();
 8         }
 9         try{
10             //調用Person類中的sayChina方法
11             Method method=demo.getMethod("sayChina");
12             method.invoke(demo.newInstance());
13             //調用Person的sayHello方法
14             method=demo.getMethod("sayHello", String.class,int.class);
15             method.invoke(demo.newInstance(),"Rollen",20);
16         }catch (Exception e) {
17             e.printStackTrace();
18         }
19     }
20 }
21 //【運行結果】:
22 //hello ,china
23 //Rollen  20
View Code

10.調用其餘類的set和get方法

 1 class hello {
 2     public static void main(String[] args) {
 3         Class<?> demo = null;
 4         Object obj=null;
 5         try {
 6             demo = Class.forName("Reflect.Person");
 7         } catch (Exception e) {
 8             e.printStackTrace();
 9         }
10         try{
11          obj=demo.newInstance();
12         }catch (Exception e) {
13             e.printStackTrace();
14         }
15         setter(obj,"Sex","男",String.class);
16         getter(obj,"Sex");
17     }
18 
19     /**
20      * @param obj   操做的對象
21      * @param att   操做的屬性
22      * */
23     public static void getter(Object obj, String att) {
24         try {
25             Method method = obj.getClass().getMethod("get" + att);
26             System.out.println(method.invoke(obj));
27         } catch (Exception e) {
28             e.printStackTrace();
29         }
30     }
31 
32     /**
33      * @param obj   操做的對象    
34      * @param att   操做的屬性
35      * @param value 設置的值
36      * @param type  參數的屬性
37      * */
38     public static void setter(Object obj, String att, Object value,
39             Class<?> type) {
40         try {
41             Method method = obj.getClass().getMethod("set" + att, type);
42             method.invoke(obj, value);
43         } catch (Exception e) {
44             e.printStackTrace();
45         }
46     }
47 }// end class
48 //【運行結果】:
49 //
View Code

11.經過反射操做屬性

 1 class hello {
 2     public static void main(String[] args) throws Exception {
 3         Class<?> demo = null;
 4         Object obj = null;
 5 
 6         demo = Class.forName("Reflect.Person");
 7         obj = demo.newInstance();
 8 
 9         Field field = demo.getDeclaredField("sex");
10         field.setAccessible(true);
11         field.set(obj, "男");
12         System.out.println(field.get(obj));
13     }
14 }// end class
View Code

12.經過反射取得並修改數組的信息

 1 import java.lang.reflect.*;
 2 
 3 class hello{
 4     public static void main(String[] args) {
 5         int[] temp={1,2,3,4,5};
 6         Class<?>demo=temp.getClass().getComponentType();
 7         System.out.println("數組類型: "+demo.getName());
 8         System.out.println("數組長度  "+Array.getLength(temp));
 9         System.out.println("數組的第一個元素: "+Array.get(temp, 0));
10         Array.set(temp, 0, 100);
11         System.out.println("修改以後數組第一個元素爲: "+Array.get(temp, 0));
12     }
13 }
14 //【運行結果】:
15 //數組類型: int
16 //數組長度  5
17 //數組的第一個元素: 1
18 //修改以後數組第一個元素爲: 100
View Code

13.經過反射修改數組大小

 1 class hello{
 2     public static void main(String[] args) {
 3         int[] temp={1,2,3,4,5,6,7,8,9};
 4         int[] newTemp=(int[])arrayInc(temp,15);
 5         print(newTemp);
 6         System.out.println("=====================");
 7         String[] atr={"a","b","c"};
 8         String[] str1=(String[])arrayInc(atr,8);
 9         print(str1);
10     }
11     /**
12      * 修改數組大小
13      * */
14     public static Object arrayInc(Object obj,int len){
15         Class<?>arr=obj.getClass().getComponentType();
16         Object newArr=Array.newInstance(arr, len);
17         int co=Array.getLength(obj);
18         System.arraycopy(obj, 0, newArr, 0, co);
19         return newArr;
20     }
21     /**
22      * 打印
23      * */
24     public static void print(Object obj){
25         Class<?>c=obj.getClass();
26         if(!c.isArray()){
27             return;
28         }
29         System.out.println("數組長度爲: "+Array.getLength(obj));
30         for (int i = 0; i < Array.getLength(obj); i++) {
31             System.out.print(Array.get(obj, i)+" ");
32         }
33     }
34 }
35 //【運行結果】:
36 //數組長度爲: 15
37 //1 2 3 4 5 6 7 8 9 0 0 0 0 0 0 =====================
38 //數組長度爲: 8
39 //a b c null null null null null
View Code

14.動態代理

首先來看看如何得到類加載器:

 1 class test{
 2 
 3 }
 4 class hello{
 5     public static void main(String[] args) {
 6         test t=new test();
 7         System.out.println("類加載器  "+t.getClass().getClassLoader().getClass().getName());
 8     }
 9 }
10 //【程序輸出】:
11 //類加載器  sun.misc.Launcher$AppClassLoader
View Code

其實在java中有三種類類加載器。

1)Bootstrap ClassLoader 此加載器採用c++編寫,通常開發中不多見。

2)Extension ClassLoader 用來進行擴展類的加載,通常對應的是jre\lib\ext目錄中的類

3)AppClassLoader 加載classpath指定的類,是最經常使用的加載器。同時也是java中默認的加載器。

若是想要完成動態代理,首先須要定義一個InvocationHandler接口的子類,已完成代理的具體操做。

 1 package Reflect;
 2 
 3 import java.lang.reflect.*;
 4 
 5 //定義項目接口
 6 interface Subject {
 7     public String say(String name, int age);
 8 }
 9 
10 // 定義真實項目
11 class RealSubject implements Subject {
12     @Override
13     public String say(String name, int age) {
14         return name + "  " + age;
15     }
16 }
17 
18 class MyInvocationHandler implements InvocationHandler {
19     private Object obj = null;
20 
21     public Object bind(Object obj) {
22         this.obj = obj;
23         return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj
24                 .getClass().getInterfaces(), this);
25     }
26 
27     @Override
28     public Object invoke(Object proxy, Method method, Object[] args)
29             throws Throwable {
30         Object temp = method.invoke(this.obj, args);
31         return temp;
32     }
33 }
34 
35 class hello {
36     public static void main(String[] args) {
37         MyInvocationHandler demo = new MyInvocationHandler();
38         Subject sub = (Subject) demo.bind(new RealSubject());
39         String info = sub.say("Rollen", 20);
40         System.out.println(info);
41     }
42 }
43 //【運行結果】:
44 //Rollen  20
View Code

類的生命週期

  在一個類編譯完成以後,下一步就須要開始使用類,若是要使用一個類,確定離不開JVM。在程序執行中JVM經過裝載,連接,初始化這3個步驟完成。

  類的裝載是經過類加載器完成的,加載器將.class文件的二進制文件裝入JVM的方法區,而且在堆區建立描述這個類的java.lang.Class對象。用來封裝數據。 可是同一個類只會被類裝載器裝載之前

連接就是把二進制數據組裝爲能夠運行的狀態。

連接分爲校驗,準備,解析這3個階段:

校驗通常用來確認此二進制文件是否適合當前的JVM(版本),

準備就是爲靜態成員分配內存空間,。並設置默認值

解析指的是轉換常量池中的代碼做爲直接引用的過程,直到全部的符號引用均可以被運行程序使用(創建完整的對應關係)。

  完成以後,類型也就完成了初始化,初始化以後類的對象就能夠正常使用了,直到一個對象再也不使用以後,將被垃圾回收。釋放空間。當沒有任何引用指向Class對象時就會被卸載,結束類的生命週期。

五. IoC原理

Spring中的IoC的實現原理就是工廠模式加反射機制。

1.咱們首先看一下不用反射機制時的工廠模式:

 1 /**
 2  * 工廠模式
 3  */
 4 interface fruit{
 5     public abstract void eat();
 6 }
 7 
 8 class Apple implements fruit{
 9     public void eat(){
10         System.out.println("Apple");
11     }
12 }
13 
14 class Orange implements fruit{
15     public void eat(){
16         System.out.println("Orange");
17     }
18 }
19 // 構造工廠類
20 // 也就是說之後若是咱們在添加其餘的實例的時候只須要修改工廠類就好了
21 class Factory{
22     public static fruit getInstance(String fruitName){
23         fruit f=null;
24         if("Apple".equals(fruitName)){
25             f=new Apple();
26         }
27         if("Orange".equals(fruitName)){
28             f=new Orange();
29         }
30         return f;
31     }
32 }
33 
34 class hello{
35     public static void main(String[] a){
36         fruit f=Factory.getInstance("Orange");
37         f.eat();
38     }
39 }

當咱們在添加一個子類的時候,就須要修改工廠類了。若是咱們添加太多的子類的時候,改的就會不少。

2. 利用反射機制的工廠模式:

 1 package Reflect;
 2 
 3 interface fruit{
 4     public abstract void eat();
 5 }
 6 
 7 class Apple implements fruit{
 8     public void eat(){
 9         System.out.println("Apple");
10     }
11 }
12 
13 class Orange implements fruit{
14     public void eat(){
15         System.out.println("Orange");
16     }
17 }
18 
19 class Factory{
20     public static fruit getInstance(String ClassName){
21         fruit f=null;
22         try{
23             f=(fruit)Class.forName(ClassName).newInstance();
24         }catch (Exception e) {
25             e.printStackTrace();
26         }
27         return f;
28     }
29 }
30 
31 class hello{
32     public static void main(String[] a){
33         fruit f=Factory.getInstance("Reflect.Apple");
34         if(f!=null){
35             f.eat();
36         }
37     }
38 }

  如今就算咱們添加任意多個子類的時候,工廠類就不須要修改。

  使用反射機制的工廠模式能夠經過反射取得接口的實例,可是須要傳入完整的包和類名。並且用戶也沒法知道一個接口有多少個可使用的子類,因此咱們經過屬性文件的形式配置所須要的子類。

3.使用反射機制並結合屬性文件的工廠模式(即IoC)

首先建立一個fruit.properties的資源文件:

1 apple=Reflect.Apple
2 orange=Reflect.Orange

而後編寫主類代碼:

 1 package Reflect;
 2 
 3 import java.io.*;
 4 import java.util.*;
 5 
 6 interface fruit{
 7     public abstract void eat();
 8 }
 9 
10 class Apple implements fruit{
11     public void eat(){
12         System.out.println("Apple");
13     }
14 }
15 
16 class Orange implements fruit{
17     public void eat(){
18         System.out.println("Orange");
19     }
20 }
21 //操做屬性文件類
22 class init{
23     public static Properties getPro() throws FileNotFoundException, IOException{
24         Properties pro=new Properties();
25         File f=new File("fruit.properties");
26         if(f.exists()){
27             pro.load(new FileInputStream(f));
28         }else{
29             pro.setProperty("apple", "Reflect.Apple");
30             pro.setProperty("orange", "Reflect.Orange");
31             pro.store(new FileOutputStream(f), "FRUIT CLASS");
32         }
33         return pro;
34     }
35 }
36 
37 class Factory{
38     public static fruit getInstance(String ClassName){
39         fruit f=null;
40         try{
41             f=(fruit)Class.forName(ClassName).newInstance();
42         }catch (Exception e) {
43             e.printStackTrace();
44         }
45         return f;
46     }
47 }
48 
49 class hello{
50     public static void main(String[] a) throws FileNotFoundException, IOException{
51         Properties pro=init.getPro();
52         fruit f=Factory.getInstance(pro.getProperty("apple"));
53         if(f!=null){
54             f.eat();
55         }
56     }
57 }
58 //【運行結果】:Apple

 

參考:http://blog.sina.com.cn/s/blog_636415010100v4gr.html

http://blog.csdn.net/liujiahan629629/article/details/18013523

http://www.cnblogs.com/jqyp/archive/2012/03/29/2423112.html

http://www.cnblogs.com/rollenholt/archive/2011/09/02/2163758.html

相關文章
相關標籤/搜索