本篇文章依舊采用小例子來說明,因為我始終覺的,案例驅動是最好的,要不然只看理論的話,看了也不懂,不過建議大家在看完文章之后,在回過頭去看看理論,會有更好的理解。
下面開始正文。
【案例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
|
public Person(String name, int age) { this .age=age; this .name=name; } |
然后繼續運行上面的程序,會出現:
所以大家以后再編寫使用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(); } } } |
【案例】接下來讓我們取得其他類的全部屬性吧,最后我講這些整理在一起,也就是通過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, 0 , 100 ); 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對象時就會被卸載,結束類的生命周期
將反射用于工廠模式
先來看看,如果不用反射的時候,的工廠模式吧:
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(); } } } |
以上這篇java反射深入剖析(推薦)就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支持服務器之家。