java 之 反射
反射是個什么東西,就是探測一個類或者接口等等這些東西的內部構造,比如知道某個類都有什么構造方法,或者有什么成員變量(你沒有他們的源代碼)。
也可以在程序運行時,動態的改變程序內部結構,而不是編譯時。
2 import java.lang.reflect.Field;
3 import java.lang.reflect.Method;
4
5 public class Test {
6 static int step = 0;
7
8 // 只要這個類被加載,就會執行一下靜態內容,不管你有沒有創建實例!
9 static {
10 System.out.println(++step + ":Test的static內容");
11 }
12
13 public Test() {
14 System.out.println(++step + ":Test的構造方法");
15 }
16
17 /**
18 * @param args
19 * @throws ClassNotFoundException
20 */
21 public static void main(String[] args) throws ClassNotFoundException {
22 // TODO Auto-generated method stub
23 System.out.println(++step + ":main的第一行");
24
25 Test test = new Test();
26
27 // 首先看怎樣使用反射,Class類
28 Class<?> c1;
29
30 // 兩種方法獲得Class對象
31 // 第一種方法,已經有了這種類的對象,那么通過getClass即可獲得
32 c1 = (test.new Lexus("凌志")).getClass(); // 對于實例化一個內部類的匿名對象,使用它上層類的實例.new就行了
33
34 System.out.println();
35 System.out.println("類名:" + c1.getName());
36
37 // 獲取內部所有有屬性
38 Field[] fs = c1.getFields();
39 System.out.println("\t+屬性:");
40 for (Field f : fs) {
41 System.out.println("\t-" + f.toGenericString());
42 }
43
44 // 獲取私有的字段
45 fs = c1.getDeclaredFields();
46 System.out.println("\t+私有屬性:");
47 for (Field f : fs) {
48 System.out.println("\t-" + f.toGenericString());
49 }
50
51 // 獲取構造方法
52 Constructor[] cts = c1.getConstructors();
53 System.out.println("\t+構造方法:");
54 for (Constructor c : cts) {
55 System.out.println("\t-" + c.toGenericString());
56 }
57
58 // 獲取所有方法
59 Method[] mds = c1.getMethods();
60 System.out.println("\t+方法:");
61 for (Method m : mds) {
62 System.out.println("\t-" + m.toGenericString());
63 }
64
65 // 獲取超類
66 Class su = c1.getSuperclass();
67 System.out.println();
68 System.out.println("類名:" + su.getName());
69 // 獲取內部所有非私有屬性
70 fs = c1.getFields();
71
72 for (Field f : fs) {
73 System.out.println("\t-" + f.toGenericString());
74 }
75
76 // ------------------------------------------//
77 // 第二種方法獲取class;
78 c1 = Class.forName("Test$Lexus"); // 內部類,不不是用.表示,而是用美元表示!
79 System.out.println("\n" + c1.getName());
80
81 }
82
83 // 機動車抽象內部類
84 public abstract class Auto {
85 public String name;
86
87 public void setName(String name) {
88 this.name = name;
89 }
90
91 public Auto(String name) {
92 setName(name);
93 }
94
95 // 啟動
96 public abstract void start();
97
98 // 熄火
99 public abstract void stop();
100
101 @Override
102 public String toString() {
103 return name;
104
105 }
106
107 }
108
109 // 內部接口,特技車輛
110 public interface Sport {
111 // 特技駕駛
112 public void specialRun(String run);
113 }
114
115 // 一輛原廠Lexus,繼承于機動車Auto
116 public class Lexus extends Auto {
117 private String nothing = "nothing";
118
119 public Lexus(String name) {
120 super(name);
121 }
122
123 @Override
124 public void start() {
125 // TODO Auto-generated method stub
126 System.out.println("->發動");
127
128 }
129
130 @Override
131 public void stop() {
132 // TODO Auto-generated method stub
133 System.out.println("->熄火");
134 }
135
136 }
137
138 // 運動版
139 public class LexusSport extends Lexus implements Sport {
140
141 public LexusSport(String name) {
142 super(name);
143 // TODO Auto-generated constructor stub
144 }
145
146 // 特種駕駛
147 @Override
148 public void specialRun(String run) {
149 // TODO Auto-generated method stub
150 System.out.println("->" + run);
151 }
152
153 }
154
155 }
返回:
2:main的第一行 //開始運行了
3:Test的構造方法 //這時,Test才被創建一個實例
類名:Test$Lexus
+屬性:
-public java.lang.String Test$Auto.name
+私有屬性:
-private java.lang.String Test$Lexus.nothing
-final Test Test$Lexus.this$0
+構造方法:
-public Test$Lexus(Test,java.lang.String)
+方法:
-public void Test$Lexus.start()
-public void Test$Lexus.stop()
-public java.lang.String Test$Auto.toString()
-public void Test$Auto.setName(java.lang.String)
-public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
-public final void java.lang.Object.wait() throws java.lang.InterruptedException
-public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
-public boolean java.lang.Object.equals(java.lang.Object)
-public native int java.lang.Object.hashCode()
-public final native java.lang.Class<?> java.lang.Object.getClass()
-public final native void java.lang.Object.notify()
-public final native void java.lang.Object.notifyAll()
類名:Test$Auto
-public java.lang.String Test$Auto.name
Test$Lexus //這是使用Class的靜態方法獲得的class對象,注意的是,如果是包含關系用的是美元$,而不是dot.
上面的示例,說明如何探查一個類的面目,下面我們知道了要探查類的內部結構,就開始去做一些有意義的事了什么是有意義的事?我們探查一個類,不只是看看這么簡單吧。。。。
2 import java.lang.reflect.Field;
3 import java.lang.reflect.InvocationTargetException;
4 import java.lang.reflect.Method;
5
6 public class Test {
7 static int step = 0;
8
9 public Test() {
10 System.out.println("Test的構造方法被調用");
11 }
12
13 /**
14 * @param args
15 * @throws ClassNotFoundException
16 * @throws NoSuchFieldException
17 * @throws SecurityException
18 * @throws IllegalAccessException
19 * @throws IllegalArgumentException
20 * @throws NoSuchMethodException
21 * @throws InvocationTargetException
22 */
23 public static void main(String[] args) throws ClassNotFoundException, SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
24 // TODO Auto-generated method stub
25 Test.LexusSport ls=new Test().new LexusSport("凌志超級運動版");
26 System.out.println();
27 //獲取實例ls的Class
28 Class<?> lc=ls.getClass();
29 System.out.println(lc.toString());
30
31 //獲取字段名為name的字段
32 Field f=lc.getField("name");
33 //獲取Test.LexusSport的實例ls的字段值
34 System.out.println(f.toGenericString()+":"+f.get(ls));
35
36 //我們現在通過對象改變一下字段值
37 ls.setName("運動版");
38 System.out.println("通過對象改變值:"+ls);
39 System.out.println(f.toGenericString()+":"+f.get(ls));
40
41 //現在通過反射,來改變字段的值
42 f.set(ls, "凌志");
43 System.out.println("通過反射改變值:"+ls);
44 System.out.println(f.toGenericString()+":"+f.get(ls));
45
46
47 //下面我們來通過反射執行方法
48 Method m=lc.getMethod("setName", String.class); //第二參數是可變參數
49 System.out.println("\n\n"+m.toGenericString());
50
51 //通過反射調用這個方法
52 m.invoke(ls, "汽車");
53 System.out.println("通過反射調用方法:"+ls);
54 System.out.println(f.toGenericString()+":"+f.get(ls));
55 }
56
57 // 機動車抽象內部類
58 public abstract class Auto {
59 public String name;
60
61 public void setName(String name) {
62 this.name = name;
63 }
64
65 public Auto(String name) {
66 System.out.println("Auto的構造方法被調用");
67 setName(name);
68 }
69
70 // 啟動
71 public abstract void start();
72
73 // 熄火
74 public abstract void stop();
75
76 @Override
77 public String toString() {
78 return name;
79
80 }
81
82 }
83
84 // 內部接口,特技車輛
85 public interface Sport {
86 // 特技駕駛
87 public void specialRun(String run);
88 }
89
90 // 一輛原廠Lexus,繼承于機動車Auto
91 public class Lexus extends Auto {
92 private String nothing = "nothing";
93
94 public Lexus(String name) {
95 super(name);
96 System.out.println("Lexus的構造方法被調用");
97
98 }
99
100 @Override
101 public void start() {
102 // TODO Auto-generated method stub
103 System.out.println("->發動");
104
105 }
106
107 @Override
108 public void stop() {
109 // TODO Auto-generated method stub
110 System.out.println("->熄火");
111 }
112
113 }
114
115 // 運動版
116 public class LexusSport extends Lexus implements Sport {
117
118 public LexusSport(String name) {
119 super(name);
120 System.out.println("LexusSport的構造方法被調用");
121
122 // TODO Auto-generated constructor stub
123 }
124
125 // 特種駕駛
126 @Override
127 public void specialRun(String run) {
128 // TODO Auto-generated method stub
129 System.out.println("->" + run);
130 }
131
132 }
133
134 }
返回:
Auto的構造方法被調用
Lexus的構造方法被調用
LexusSport的構造方法被調用
//這里順便了解到,每個對象是從基類開始初始化的
class Test$LexusSport
public java.lang.String Test$Auto.name:凌志超級運動版
通過對象改變值:運動版
public java.lang.String Test$Auto.name:運動版
通過反射改變值:凌志
public java.lang.String Test$Auto.name:凌志
public void Test$Auto.setName(java.lang.String)
通過反射調用方法:汽車
public java.lang.String Test$Auto.name:汽車
調用構造方法,就不寫了,也就是Class的這個方法調用了構造方法后,返回的是一個新建了的對象的引用,也就是句柄,和new 一個對象效果一樣。
現在,我們窺探了Class反射,用在什么地方呢??
很多回答是框架,怎么回事呢?
網上的回答都弱爆了。我的拙見:
框架就好像一套智能建筑物的框架,承重的框架當然給你提供好了,你給里面砌墻裝潢去,想怎么折騰怎么折騰。那么和反射有什么呢?
比如,有一個框架,你往里面砌一堵墻,你的墻名字(類名)是“碳纖維墻”,你這樣告訴他“我在一層的最左邊砌一堵碳纖維墻”,他就會為你找碳纖維,并把這堵墻放到你期望的位置,他如何實現呢?首先分析你的話語,他必須要找到碳纖維并做成墻,翻譯成基本的java語言,就是“new CarbonWall”,java沒有提供根據字符串來判斷類名,然后new的語句吧,這就需要用到映射了,Class.forName("CarbonWall"),然后調用構造函數。。。。。。。。然后。。。然后。。。。。
現在,就恍然大悟了,原來每個大樓框架的對面都有一面很大的鏡子,框架無法看清自己每個樓層的東西,因為他的頭在最上面啊,剛好java提供了這面鏡子讓框架能看清自己,就是反射了。
除了框架,還有些應用,看代碼:
2 import java.lang.reflect.Field;
3 import java.lang.reflect.InvocationTargetException;
4 import java.lang.reflect.Method;
5 import java.lang.reflect.Type;
6 import java.util.List;
7
8 public class Test {
9 static int step = 0;
10
11
12 /**
13 * @param args
14 * @throws ClassNotFoundException
15 * @throws NoSuchFieldException
16 * @throws SecurityException
17 * @throws IllegalAccessException
18 * @throws IllegalArgumentException
19 * @throws NoSuchMethodException
20 * @throws InvocationTargetException
21 */
22 public static void main(String[] args) throws ClassNotFoundException, SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
23 // TODO Auto-generated method stub
24 //現在要舉行汽車運動會,一大堆車報名參加
25 Test.LexusSport car1=new Test().new LexusSport("凌志超級運動版 1");
26 Test.LexusSport car2=new Test().new LexusSport("凌志超級運動版 2");
27 Test.Lexus car3=new Test().new Lexus("凌志 3");
28 Test.Moto car4=new Test().new Moto("哈雷4");
29
30 //現在所有車輛進入競技場
31 Auto[] arena=new Auto[4];
32 arena[0]=car1;
33 arena[1]=car2;
34 arena[2]=car3;
35 arena[3]=car4;
36
37
38
39
40 //一聲令下
41 System.out.println("開始:");
42 for(int i=0;i<arena.length;i++){
43 arena[i].start();
44 }
45 System.out.println("\n\n");
46
47 //現在開始表演特技,兩輪著地
48
49 //問題出來了,Lexus沒有實現sport接口,它不可能兩輪著地
50 //而moto摩托兩輪著地無意義,他本來就是兩個輪子著地
51 //但是,現在命令全場的車都兩輪著地,每個類都實現一個方法來判斷能否兩輪著地嗎?
52 //上面復雜了,這時,反射上場!
53 for(int i=0;i<arena.length;i++){
54 //獲取所有的實現的接口的數組
55 Type[] ts=arena[i].getClass().getGenericInterfaces();
56 for(Type t:ts){
57 //遍歷已經實現的接口,倘若有Sport的接口,則通過反射調用specialRun方法
58 if(t.toString().equals("interface Test$Sport")){
59 arena[i].getClass().getMethod("specialRun", String.class).invoke(arena[i], "兩輪著地!");
60 break;
61 }
62 }
63
64 }
65
66 //好了,比賽結束!
67 System.out.println("\n\n");
68 for(int i=0;i<arena.length;i++){
69 arena[i].stop();
70 }
71
72
73 }
74
75 // 機動車抽象內部類
76 public abstract class Auto {
77 public String name;
78
79 public void setName(String name) {
80 this.name = name;
81 }
82
83 public Auto(String name) {
84 setName(name);
85 }
86
87 // 啟動
88 public abstract void start();
89
90 // 熄火
91 public abstract void stop();
92
93 @Override
94 public String toString() {
95 return name;
96
97 }
98
99 }
100
101 // 內部接口,特技車輛
102 public interface Sport {
103 // 特技駕駛
104 public void specialRun(String run);
105 }
106
107 // 一輛原廠Lexus,繼承于機動車Auto
108 public class Lexus extends Auto {
109
110 public Lexus(String name) {
111 super(name);
112
113 }
114
115 @Override
116 public void start() {
117 // TODO Auto-generated method stub
118 System.out.println(this+"->用鑰匙發動");
119
120 }
121
122 @Override
123 public void stop() {
124 // TODO Auto-generated method stub
125 System.out.println(this+"->熄火");
126 }
127
128 }
129
130 // 運動版
131 public class LexusSport extends Lexus implements Sport {
132
133 public LexusSport(String name) {
134 super(name);
135
136 // TODO Auto-generated constructor stub
137 }
138
139 // 特種駕駛
140 @Override
141 public void specialRun(String run) {
142 // TODO Auto-generated method stub
143 System.out.println(this+"->" + run);
144 }
145
146 }
147
148 //摩托車
149 public class Moto extends Auto{
150
151 public Moto(String name) {
152 super(name);
153 // TODO Auto-generated constructor stub
154 }
155
156
157 @Override
158 public void start() {
159 // TODO Auto-generated method stub
160 System.out.println(this+"->用腳發動");
161 }
162
163 @Override
164 public void stop() {
165 // TODO Auto-generated method stub
166 System.out.println(this+"->熄火");
167 }
168
169 }
170
171 }
返回:
凌志超級運動版 1->用鑰匙發動
凌志超級運動版 2->用鑰匙發動
凌志 3->用鑰匙發動
哈雷4->用腳發動
凌志超級運動版 1->兩輪著地!
凌志超級運動版 2->兩輪著地!
//摩托車不用強調,顯而易見的,兩輪
凌志超級運動版 1->熄火
凌志超級運動版 2->熄火
凌志 3->熄火
哈雷4->熄火
這個例子是什么設計模式?
在《Thingking in Java 4th》中的例子是,是畫布,意思是,在畫布上有多個圖形,現在要旋轉每個圖像,三角形四方形等實現了旋轉接口,圓形旋轉沒有意義,難道要讓圓形也實現旋轉接口么?不用,用反射就行了。和上面基本差不多。
浙公網安備 33010602011771號