java 反射機制詳解--概念+例子

原文鏈接:http://www.cnblogs.com/jqyp/archive/2012/03/29/2423112.html
http://www.cnblogs.com/rollenholt/archive/2011/09/02/2163758.html

一、什麼是反射機制 
        簡單的來說,反射機制指的是程序在運行時能夠獲取自身的信息。在java中,只要給定類的名字, 
    那麼就可以通過反射機制來獲得類的所有信息。 
二、哪裏用到反射機制 
        有些時候,我們用過一些知識,但是並不知道它的專業術語是什麼,在剛剛學jdbc時用過一行代碼, 
    Class.forName("com.mysql.jdbc.Driver.class").newInstance();但是那時候只知道那行代碼是生成 
    驅動對象實例,並不知道它的具體含義。聽了反射機制這節課後,才知道,原來這就是反射,現在很多開 
    框架都用到反射機制,hibernate、struts都是用反射機制實現的。 
三、反射機制的優點與缺點 
        爲什麼要用反射機制?直接創建對象不就可以了嗎,這就涉及到了動態與靜態的概念, 
    靜態編譯:在編譯時確定類型,綁定對象,即通過。 
    動態編譯:運行時確定類型,綁定對象。動態編譯最大限度發揮了java的靈活性,體現了多 
    態的應用,有以降低類之間的藕合性。 
    一句話,反射機制的優點就是可以實現動態創建對象和編譯,體現出很大的靈活性,特別是在J2EE的開發中 
    它的靈活性就表現的十分明顯。比如,一個大型的軟件,不可能一次就把把它設計的很完美,當這個程序編 
    譯後,發佈了,當發現需要更新某些功能時,我們不可能要用戶把以前的卸載,再重新安裝新的版本,假如 
    這樣的話,這個軟件肯定是沒有多少人用的。採用靜態的話,需要把整個程序重新編譯一次纔可以實現功能 
    的更新,而採用反射機制的話,它就可以不用卸載,只需要在運行時才動態的創建和編譯,就可以實現該功 
    能。 
       它的缺點是對性能有影響。使用反射基本上是一種解釋操作,我們可以告訴JVM,我們希望做什麼並且它 
    滿足我們的要求。這類操作總是慢於只直接執行相同的操作。 
四、利用反射機制能獲得什麼信息 
         一句話,類中有什麼信息,它就可以獲得什麼信息,不過前提是得知道類的名字,要不就沒有後文了 
    首先得根據傳入的類的全名來創建Class對象。 
    Class c=Class.forName("className");註明:className必須爲全名,也就是得包含包名,比如,cn.netjava.pojo.UserInfo; 
    Object obj=c.newInstance();//創建對象的實例 
    OK,有了對象就什麼都好辦了,想要什麼信息就有什麼信息了。   
    獲得構造函數的方法 
    Constructor getConstructor(Class[] params)//根據指定參數獲得public構造器

    Constructor[] getConstructors()//獲得public的所有構造器

    Constructor getDeclaredConstructor(Class[] params)//根據指定參數獲得public和非public的構造器

    Constructor[] getDeclaredConstructors()//獲得public的所有構造器 
    獲得類方法的方法 
    Method getMethod(String name, Class[] params),根據方法名,參數類型獲得方法

    Method[] getMethods()//獲得所有的public方法

    Method getDeclaredMethod(String name, Class[] params)//根據方法名和參數類型,獲得public和非public的方法

    Method[] getDeclaredMethods()//獲得所以的public和非public方法 
    獲得類中屬性的方法 
    Field getField(String name)//根據變量名得到相應的public變量

    Field[] getFields()//獲得類中所以public的方法

    Field getDeclaredField(String name)//根據方法名獲得public和非public變量

    Field[] getDeclaredFields()//獲得類中所有的public和非public方法 
    常用的就這些,知道這些,其他的都好辦…… 


本篇文章依舊採用小例子來說明,因爲我始終覺的,案例驅動是最好的,要不然只看理論的話,看了也不懂,不過建議大家在看完文章之後,在回過頭去看看理論,會有更好的理解。

下面開始正文。

【案例1】通過一個對象獲得完整的包名和類名

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package Reflect;
 
/**
 * 通過一個對象獲得完整的包名和類名
 * */
class Demo{
    //other codes...
}
 
class hello{
    public static void main(String[] args) {
        Demo demo=new Demo();
        System.out.println(demo.getClass().getName());
    }
}

【運行結果】:Reflect.Demo

添加一句:所有類的對象其實都是Class的實例。

【案例2】實例化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
package Reflect;
class Demo{
    //other codes...
}
 
class hello{
    public static void main(String[] args) {
        Class<?> demo1=null;
        Class<?> demo2=null;
        Class<?> demo3=null;
        try{
            //一般儘量採用這種形式
            demo1=Class.forName("Reflect.Demo");
        }catch(Exception e){
            e.printStackTrace();
        }
        demo2=new Demo().getClass();
        demo3=Demo.class;
         
        System.out.println("類名稱   "+demo1.getName());
        System.out.println("類名稱   "+demo2.getName());
        System.out.println("類名稱   "+demo3.getName());
         
    }
}

【運行結果】:

類名稱   Reflect.Demo

類名稱   Reflect.Demo

類名稱   Reflect.Demo

【案例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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
package Reflect;
 
class Person{
     
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    @Override
    public String toString(){
        return "["+this.name+"  "+this.age+"]";
    }
    private String name;
    private int age;
}
 
class hello{
    public static void main(String[] args) {
        Class<?> demo=null;
        try{
            demo=Class.forName("Reflect.Person");
        }catch (Exception e) {
            e.printStackTrace();
        }
        Person per=null;
        try {
            per=(Person)demo.newInstance();
        catch (InstantiationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        per.setName("Rollen");
        per.setAge(20);
        System.out.println(per);
    }
}

【運行結果】:

[Rollen  20]

但是注意一下,當我們把Person中的默認的無參構造函數取消的時候,比如自己定義只定義一個有參數的構造函數之後,會出現錯誤:

比如我定義了一個構造函數:

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

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

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實例化其他類的對象的時候,一定要自己定義無參的構造函數

 

【案例】通過Class調用其他類中的構造函數 (也可以通過這種方式通過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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
package Reflect;
 
import java.lang.reflect.Constructor;
 
class Person{
     
    public Person() {
         
    }
    public Person(String name){
        this.name=name;
    }
    public Person(int age){
        this.age=age;
    }
    public Person(String name, int age) {
        this.age=age;
        this.name=name;
    }
    public String getName() {
        return name;
    }
    public int getAge() {
        return age;
    }
    @Override
    public String toString(){
        return "["+this.name+"  "+this.age+"]";
    }
    private String name;
    private int age;
}
 
class hello{
    public static void main(String[] args) {
        Class<?> demo=null;
        try{
            demo=Class.forName("Reflect.Person");
        }catch (Exception e) {
            e.printStackTrace();
        }
        Person per1=null;
        Person per2=null;
        Person per3=null;
        Person per4=null;
        //取得全部的構造函數
        Constructor<?> cons[]=demo.getConstructors();
        try{
            per1=(Person)cons[0].newInstance();
            per2=(Person)cons[1].newInstance("Rollen");
            per3=(Person)cons[2].newInstance(20);
            per4=(Person)cons[3].newInstance("Rollen",20);
        }catch(Exception e){
            e.printStackTrace();
        }
        System.out.println(per1);
        System.out.println(per2);
        System.out.println(per3);
        System.out.println(per4);
    }
}

【運行結果】:

[null  0]

[Rollen  0]

[null  20]

[Rollen  20]

【案例】 

返回一個類實現的接口:

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
package Reflect;
 
interface China{
    public static final String name="Rollen";
    public static  int age=20;
    public void sayChina();
    public void sayHello(String name, int age);
}
 
class Person implements China{
    public Person() {
         
    }
    public Person(String sex){
        this.sex=sex;
    }
    public String getSex() {
        return sex;
    }
    public void setSex(String sex) {
        this.sex = sex;
    }
    @Override
    public void sayChina(){
        System.out.println("hello ,china");
    }
    @Override
    public void sayHello(String name, int age){
        System.out.println(name+"  "+age);
    }
    private String sex;
}
 
class hello{
    public static void main(String[] args) {
        Class<?> demo=null;
        try{
            demo=Class.forName("Reflect.Person");
        }catch (Exception e) {
            e.printStackTrace();
        }
        //保存所有的接口
        Class<?> intes[]=demo.getInterfaces();
        for (int i = 0; i < intes.length; i++) {
            System.out.println("實現的接口   "+intes[i].getName());
        }
    }
}

【運行結果】:

實現的接口   Reflect.China

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

【案例】:取得其他類中的父類

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

【運行結果】

繼承的父類爲:   java.lang.Object

【案例】:獲得其他類中的全部構造函數

這個例子需要在程序開頭添加import java.lang.reflect.*;

然後將主類編寫爲:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class hello{
    public static void main(String[] args) {
        Class<?> demo=null;
        try{
            demo=Class.forName("Reflect.Person");
        }catch (Exception e) {
            e.printStackTrace();
        }
        Constructor<?>cons[]=demo.getConstructors();
        for (int i = 0; i < cons.length; i++) {
            System.out.println("構造方法:  "+cons[i]);
        }
    }
}

【運行結果】:

構造方法:  public Reflect.Person()

構造方法:  public Reflect.Person(java.lang.String)

但是細心的讀者會發現,上面的構造函數沒有public 或者private這一類的修飾符

下面這個例子我們就來獲取修飾符

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
class hello{
    public static void main(String[] args) {
        Class<?> demo=null;
        try{
            demo=Class.forName("Reflect.Person");
        }catch (Exception e) {
            e.printStackTrace();
        }
        Constructor<?>cons[]=demo.getConstructors();
        for (int i = 0; i < cons.length; i++) {
            Class<?> p[]=cons[i].getParameterTypes();
            System.out.print("構造方法:  ");
            int mo=cons[i].getModifiers();
            System.out.print(Modifier.toString(mo)+" ");
            System.out.print(cons[i].getName());
            System.out.print("(");
            for(int j=0;j<p.length;++j){
                System.out.print(p[j].getName()+" arg"+i);
                if(j<p.length-1){
                    System.out.print(",");
                }
            }
            System.out.println("){}");
        }
    }
}

【運行結果】:

構造方法:  public Reflect.Person(){}

構造方法:  public Reflect.Person(java.lang.String arg1){}

有時候一個方法可能還有異常,呵呵。下面看看:

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
33
34
35
36
37
38
39
class hello{
    public static void main(String[] args) {
        Class<?> demo=null;
        try{
            demo=Class.forName("Reflect.Person");
        }catch (Exception e) {
            e.printStackTrace();
        }
        Method method[]=demo.getMethods();
        for(int i=0;i<method.length;++i){
            Class<?> returnType=method[i].getReturnType();
            Class<?> para[]=method[i].getParameterTypes();
            int temp=method[i].getModifiers();
            System.out.print(Modifier.toString(temp)+" ");
            System.out.print(returnType.getName()+"  ");
            System.out.print(method[i].getName()+" ");
            System.out.print("(");
            for(int j=0;j<para.length;++j){
                System.out.print(para[j].getName()+" "+"arg"+j);
                if(j<para.length-1){
                    System.out.print(",");
                }
            }
            Class<?> exce[]=method[i].getExceptionTypes();
            if(exce.length>0){
                System.out.print(") throws ");
                for(int k=0;k<exce.length;++k){
                    System.out.print(exce[k].getName()+" ");
                    if(k<exce.length-1){
                        System.out.print(",");
                    }
                }
            }else{
                System.out.print(")");
            }
            System.out.println();
        }
    }
}

【運行結果】:

public java.lang.String  getSex ()

public void  setSex (java.lang.String arg0)

public void  sayChina ()

public void  sayHello (java.lang.String arg0,int arg1)

public final native void  wait (long arg0) throws java.lang.InterruptedException

public final void  wait () throws java.lang.InterruptedException

public final void  wait (long arg0,int arg1) throws java.lang.InterruptedException

public boolean  equals (java.lang.Object arg0)

public java.lang.String  toString ()

public native int  hashCode ()

public final native java.lang.Class  getClass ()

public final native void  notify ()

public final native void  notifyAll ()

【案例】接下來讓我們取得其他類的全部屬性吧,最後我講這些整理在一起,也就是通過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
26
27
28
29
30
31
32
33
34
class hello {
    public static void main(String[] args) {
        Class<?> demo = null;
        try {
            demo = Class.forName("Reflect.Person");
        catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("===============本類屬性========================");
        // 取得本類的全部屬性
        Field[] field = demo.getDeclaredFields();
        for (int i = 0; i < field.length; i++) {
            // 權限修飾符
            int mo = field[i].getModifiers();
            String priv = Modifier.toString(mo);
            // 屬性類型
            Class<?> type = field[i].getType();
            System.out.println(priv + " " + type.getName() + " "
                    + field[i].getName() + ";");
        }
        System.out.println("===============實現的接口或者父類的屬性========================");
        // 取得實現的接口或者父類的屬性
        Field[] filed1 = demo.getFields();
        for (int j = 0; j < filed1.length; j++) {
            // 權限修飾符
            int mo = filed1[j].getModifiers();
            String priv = Modifier.toString(mo);
            // 屬性類型
            Class<?> type = filed1[j].getType();
            System.out.println(priv + " " + type.getName() + " "
                    + filed1[j].getName() + ";");
        }
    }
}

【運行結果】:

===============本類屬性========================

private java.lang.String sex;

===============實現的接口或者父類的屬性========================

public static final java.lang.String name;

public static final int age;

【案例】其實還可以通過反射調用其他類中的方法:

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

  【運行結果】:

hello ,china

Rollen  20

【案例】調用其他類的set和get方法

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
class hello {
    public static void main(String[] args) {
        Class<?> demo = null;
        Object obj=null;
        try {
            demo = Class.forName("Reflect.Person");
        catch (Exception e) {
            e.printStackTrace();
        }
        try{
         obj=demo.newInstance();
        }catch (Exception e) {
            e.printStackTrace();
        }
        setter(obj,"Sex","男",String.class);
        getter(obj,"Sex");
    }
 
    /**
     * @param obj
     *            操作的對象
     * @param att
     *            操作的屬性
     * */
    public static void getter(Object obj, String att) {
        try {
            Method method = obj.getClass().getMethod("get" + att);
            System.out.println(method.invoke(obj));
        catch (Exception e) {
            e.printStackTrace();
        }
    }
 
    /**
     * @param obj
     *            操作的對象
     * @param att
     *            操作的屬性
     * @param value
     *            設置的值
     * @param type
     *            參數的屬性
     * */
    public static void setter(Object obj, String att, Object value,
            Class<?> type) {
        try {
            Method method = obj.getClass().getMethod("set" + att, type);
            method.invoke(obj, value);
        catch (Exception e) {
            e.printStackTrace();
        }
    }
}// end class

【運行結果】:

 【案例】通過反射操作屬性

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

【案例】通過反射取得並修改數組的信息:

1
2
3
4
5
6
7
8
9
10
11
12
import java.lang.reflect.*;
class hello{
    public static void main(String[] args) {
        int[] temp={1,2,3,4,5};
        Class<?>demo=temp.getClass().getComponentType();
        System.out.println("數組類型: "+demo.getName());
        System.out.println("數組長度  "+Array.getLength(temp));
        System.out.println("數組的第一個元素: "+Array.get(temp, 0));
        Array.set(temp, 0100);
        System.out.println("修改之後數組第一個元素爲: "+Array.get(temp, 0));
    }
}

【運行結果】:

數組類型: int

數組長度  5

數組的第一個元素: 1

修改之後數組第一個元素爲: 100

【案例】通過反射修改數組大小

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
33
34
35
class hello{
    public static void main(String[] args) {
        int[] temp={1,2,3,4,5,6,7,8,9};
        int[] newTemp=(int[])arrayInc(temp,15);
        print(newTemp);
        System.out.println("=====================");
        String[] atr={"a","b","c"};
        String[] str1=(String[])arrayInc(atr,8);
        print(str1);
    }
     
    /**
     * 修改數組大小
     * */
    public static Object arrayInc(Object obj,int len){
        Class<?>arr=obj.getClass().getComponentType();
        Object newArr=Array.newInstance(arr, len);
        int co=Array.getLength(obj);
        System.arraycopy(obj, 0, newArr, 0, co);
        return newArr;
    }
    /**
     * 打印
     * */
    public static void print(Object obj){
        Class<?>c=obj.getClass();
        if(!c.isArray()){
            return;
        }
        System.out.println("數組長度爲: "+Array.getLength(obj));
        for (int i = 0; i < Array.getLength(obj); i++) {
            System.out.print(Array.get(obj, i)+" ");
        }
    }
}

【運行結果】:

數組長度爲: 15

1 2 3 4 5 6 7 8 9 0 0 0 0 0 0 =====================

數組長度爲: 8

a b c null null null null null

動態代理

【案例】首先來看看如何獲得類加載器:

1
2
3
4
5
6
7
8
9
class test{
     
}
class hello{
    public static void main(String[] args) {
        test t=new test();
        System.out.println("類加載器  "+t.getClass().getClassLoader().getClass().getName());
    }
}

【程序輸出】:

類加載器  sun.misc.Launcher$AppClassLoader

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

1)Bootstrap ClassLoader 此加載器採用c++編寫,一般開發中很少見。

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

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

如果想要完成動態代理,首先需要定義一個InvocationHandler接口的子類,已完成代理的具體操作。

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
33
34
35
36
37
38
39
40
41
package Reflect;
import java.lang.reflect.*;
 
//定義項目接口
interface Subject {
    public String say(String name, int age);
}
 
// 定義真實項目
class RealSubject implements Subject {
    @Override
    public String say(String name, int age) {
        return name + "  " + age;
    }
}
 
class MyInvocationHandler implements InvocationHandler {
    private Object obj = null;
 
    public Object bind(Object obj) {
        this.obj = obj;
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj
                .getClass().getInterfaces(), this);
    }
 
    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        Object temp = method.invoke(this.obj, args);
        return temp;
    }
}
 
class hello {
    public static void main(String[] args) {
        MyInvocationHandler demo = new MyInvocationHandler();
        Subject sub = (Subject) demo.bind(new RealSubject());
        String info = sub.say("Rollen"20);
        System.out.println(info);
    }
}

【運行結果】:

Rollen  20

類的生命週期

在一個類編譯完成之後,下一步就需要開始使用類,如果要使用一個類,肯定離不開JVM。在程序執行中JVM通過裝載,鏈接,初始化這3個步驟完成。

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

鏈接就是把二進制數據組裝爲可以運行的狀態。

 

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

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

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

解析指的是轉換常量池中的代碼作爲直接引用的過程,直到所有的符號引用都可以被運行程序使用(建立完整的對應關係)

完成之後,類型也就完成了初始化,初始化之後類的對象就可以正常使用了,直到一個對象不再使用之後,將被垃圾回收。釋放空間。

當沒有任何引用指向Class對象時就會被卸載,結束類的生命週期

將反射用於工廠模式

先來看看,如果不用反射的時候,的工廠模式吧:

http://www.cnblogs.com/rollenholt/archive/2011/08/18/2144851.html

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
33
34
35
36
37
38
39
40
41
/**
 * @author Rollen-Holt 設計模式之 工廠模式
 */
 
interface fruit{
    public abstract void eat();
}
 
class Apple implements fruit{
    public void eat(){
        System.out.println("Apple");
    }
}
 
class Orange implements fruit{
    public void eat(){
        System.out.println("Orange");
    }
}
 
// 構造工廠類
// 也就是說以後如果我們在添加其他的實例的時候只需要修改工廠類就行了
class Factory{
    public static fruit getInstance(String fruitName){
        fruit f=null;
        if("Apple".equals(fruitName)){
            f=new Apple();
        }
        if("Orange".equals(fruitName)){
            f=new Orange();
        }
        return f;
    }
}
class hello{
    public static void main(String[] a){
        fruit f=Factory.getInstance("Orange");
        f.eat();
    }
 
}

這樣,當我們在添加一個子類的時候,就需要修改工廠類了。如果我們添加太多的子類的時候,改的就會很多。

現在我們看看利用反射機制:

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
33
34
35
36
37
package Reflect;
 
interface fruit{
    public abstract void eat();
}
 
class Apple implements fruit{
    public void eat(){
        System.out.println("Apple");
    }
}
 
class Orange implements fruit{
    public void eat(){
        System.out.println("Orange");
    }
}
 
class Factory{
    public static fruit getInstance(String ClassName){
        fruit f=null;
        try{
            f=(fruit)Class.forName(ClassName).newInstance();
        }catch (Exception e) {
            e.printStackTrace();
        }
        return f;
    }
}
class hello{
    public static void main(String[] a){
        fruit f=Factory.getInstance("Reflect.Apple");
        if(f!=null){
            f.eat();
        }
    }
}

現在就算我們添加任意多個子類的時候,工廠類就不需要修改。

 

上面的愛嗎雖然可以通過反射取得接口的實例,但是需要傳入完整的包和類名。而且用戶也無法知道一個接口有多少個可以使用的子類,所以我們通過屬性文件的形式配置所需要的子類。

下面我們來看看: 結合屬性文件的工廠模式

首先創建一個fruit.properties的資源文件,

內容爲:

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

 然後編寫主類代碼:

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
package Reflect;
 
import java.io.*;
import java.util.*;
 
interface fruit{
    public abstract void eat();
}
 
class Apple implements fruit{
    public void eat(){
        System.out.println("Apple");
    }
}
 
class Orange implements fruit{
    public void eat(){
        System.out.println("Orange");
    }
}
 
//操作屬性文件類
class init{
    public static Properties getPro() throws FileNotFoundException, IOException{
        Properties pro=new Properties();
        File f=new File("fruit.properties");
        if(f.exists()){
            pro.load(new FileInputStream(f));
        }else{
            pro.setProperty("apple""Reflect.Apple");
            pro.setProperty("orange""Reflect.Orange");
            pro.store(new FileOutputStream(f), "FRUIT CLASS");
        }
        return pro;
    }
}
 
class Factory{
    public static fruit getInstance(String ClassName){
        fruit f=null;
        try{
            f=(fruit)Class.forName(ClassName).newInstance();
        }catch (Exception e) {
            e.printStackTrace();
        }
        return f;
    }
}
class hello{
    public static void main(String[] a) throws FileNotFoundException, IOException{
        Properties pro=init.getPro();
        fruit f=Factory.getInstance(pro.getProperty("apple"));
        if(f!=null){
            f.eat();
        }
    }
}

【運行結果】:Apple

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章