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》中的例子是,是画布,意思是,在画布上有多个图形,现在要旋转每个图像,三角形四方形等实现了旋转接口,圆形旋转没有意义,难道要让圆形也实现旋转接口么?不用,用反射就行了。和上面基本差不多。