java 之 反射

反射是个什么东西,就是探测一个类或者接口等等这些东西的内部构造,比如知道某个类都有什么构造方法,或者有什么成员变量(你没有他们的源代码)。

也可以在程序运行时,动态的改变程序内部结构,而不是编译时。 

  1 import java.lang.reflect.Constructor;
  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 }

返回:

1:Test的static内容 //首先,main是在Test类中,Test类被加载到内存中,并初始化,但还没有被实例化
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(longthrows java.lang.InterruptedException
    
-public final void java.lang.Object.wait() throws java.lang.InterruptedException
    
-public final void java.lang.Object.wait(long,intthrows 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.

上面的示例,说明如何探查一个类的面目,下面我们知道了要探查类的内部结构,就开始去做一些有意义的事了什么是有意义的事?我们探查一个类,不只是看看这么简单吧。。。。

  1 import java.lang.reflect.Constructor;
  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 }

返回:

Test的构造方法被调用
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提供了这面镜子让框架能看清自己,就是反射了。

 

除了框架,还有些应用,看代码:

 

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

 

原文地址:https://www.cnblogs.com/hangxin1940/p/2040759.html