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

     

  • 相关阅读:
    ModelFirst的CRUD
    EF中逆变和协变
    ERP客户关系渠管理(二十)
    ERP反馈信息管理(十九)
    ERP系统上传文档信息下载(十八)
    比较 数组与对象的同源特性
    对android的认识
    我的知乎
    HTTP来源地址
    BroadcastReceiver 翻译
  • 原文地址:https://www.cnblogs.com/hangxin1940/p/2040759.html
Copyright © 2011-2022 走看看