JAVA-反射机制

来源:互联网 发布:数控车g92管螺纹编程 编辑:程序博客网 时间:2024/06/06 14:08

预备知识

OK,言归正传,首先我们先了解下什么是JAVA的反射机制,更多的概念性东西请前往百度百科,的确土了点: http://baike.baidu.com/view/1865203.htm?fr=aladdin

接下来我从这些繁杂的文字当中自己小小地总结一些要点:

  •  如何理解反射?

JAVA之所以引入一个reflect的概念,尤其强调的是reflect这个单词的象征性含义,简单说就是JAVA的程序在运行的过程中同样提供了一个自己的镜像一般的“影子”–计算机领域把这种特点称之为self-representation(自省或自表达),在这个过程中,开发人员从“影子”中便可获得JAVA实体运行程序的全部属性,并且允许开发再去修改这些属性。

  • 为什么JAVA会引入反射机制?

其实说到这个问题,不得不说JAVA引入这个机制的目的其实是为了顺应潮流,弥补自己的软肋,平时大家可能听说过静态语言与动态语言的划分问题,这又是一个很蛋疼的概念性问题,还是给个链接,感兴趣的话各位测友自己去翻阅看看:http://baike.baidu.com/view/1458275.htm  ,那么其实你会发现,JAVA(C#也一样)其实是介于这种静态与动态之间的语言,然而其实现在的系统或者框架以至于模块都趋向对外开放的可拓展性,这是动态语言的优势(测友的最爱python还有笔者曾经用过的ruby就是典型的动态语言),所以JAVA选择反射机制来让自己“显得”很像动态语言,请注意我这里的措辞。这种可能性的确是一种进步,但是反射机制不是一个性能很高的行为特点,因此要巧妙而冷静地去应用。

  • 我们利用JAVA反射都干些什么事情呢?

一般情况下,我们会利用这一个特性,获取一个JAVA Class下的全部属性信息(类信息,类变量,所有的方法信息,所有的注解信息等,并且我们还能修改他们),可能这样解释还不直观,说几个利用反射机制你能干的事情吧,比如你想列出来一个类下所有的方法,就如同你在一些IDE中能够看到一个Class下的树状结构一样,那么利用JAVA反射机制便可以实现这个功能;如果您使用过JDBC去和数据库打交道的话,不知道您是否还记得如何加载实例化DB驱动的环节(如:Class.forName(“com.mysql.jdbc.Driver.class”).newInstance();),其实我现在才知道,这就是一个典型的JAVA反射机制的应用,以后可以装下B了,呵呵;JAVA反射机制的经典应用还出现在著名的JAVA web类明星企业级应用开发框架组合SSH中,以Hibernate为例,该框架大量的使用了JAVA的反射机制来动态的加载并执行不同的函数,让JAVA的接口和抽象类的定义在实践中发挥到了极致,利用JAVA反射机制完成的基础代码架构的部分几乎不需要过多的修改便可以满足新增的需求(打断一下,这里说一个现实,其实JAVA的反射机制的确是在框架类代码中才被广泛使用,如果只是应用级别的人,比如几个做APP的小开发人员,我想他们也许只是知道这个东西,是否在应用我可以画一个大大的问号,作为测试人员的我们,能真正实践的可能更是少数),当然这也是我们测试框架一直追求的–高可复用性,高可拓展性,高可维护性,现实中其实我自己却很少应用,以后如果在做小的测试工具和所谓的测试框架时,我也要强迫自己应用这些特点,至少也能跟的上那些学院派大牛的步伐。

  • JAVA反射机制应用的一般设计步骤
  1. 先获取Class(可利用Class.forName;Object.class;Object.TYPE)
  2. 实例化Class对象(利用newInstance())
  3. 这时就厉害了,你将可以获得此类下的各种信息(包括:Constructor(构造函数),Method (所有已定义的方法),Field (所有类的属性,包括类中的变量))
  4. 接下来你便可以无法无天了
  • JAVA反射机制应用过程中的不安全因素

聪明的测友也许会感受到一个问题,那就是你会发现因为有了JAVA的反射机制,那些所谓的public,private可见性限制及作用域问题都变的形同虚设一样,当然sun公司不可能无视这些东西,因此伟大的sun公司创建了一个类AccessibleObject,提供了一个方法setAccessible来避免滥用反射带来的安全隐患。其实这个应用是很难的一件事情,非技术细节狂人还是不要去触碰为好,我只是轻轻地了解了一下这个东西(这几周由于测试执行性能方面的限制,我把一个单线程的测试工具的代码改为多线程都各种坑需要填,对于这个反射安全性的应用,鄙人还是飘过为妙)。

反射实践

如果上面的废话很多很讨厌的话,那么“show me your code”更务实一些,所有的实践和理解都写在这里。。。
接上次的工厂类设计模式,这里当是复习一下:

Demo Code:

  • 创建接口
123456
public interface TestingListener {//一个伪测试状态监视器的接口定义        public void startListener();        public void stopListener();        public int getTestingStatusCode(String status);}
  • 实现接口

GUI层测试状态监视器

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
public class GuiFunctiontestingListener implements TestingListener{//这是一个GUI层的QA验证程序的状态监听器        boolean isStarted = false;        boolean isEnded = false;        @Override        public void startListener() {            // TODO Auto-generated method stub            long startTime = System.currentTimeMillis();            if(isStarted == false){                System.out.println(">>>Start listener=>GuiFunctiontestingListener");                isStarted = true;                isEnded = false;            }            if(this.isStarted){                try {//假启动时间                    Thread.sleep(3000);                } catch (InterruptedException e) {                    e.printStackTrace();                }            long endTime = System.currentTimeMillis() - startTime;                    System.out.println(">>>listener=>GuiFunctiontestingListener started!Time costing:"+endTime+" ms");            }else{                System.err.println(">>>listener=>GuiFunctiontestingListener starting meet trouble!");            }        }         @Override        public void stopListener() {            // TODO Auto-generated method stub            long startTime = System.currentTimeMillis();            if(isEnded == false){                System.out.println(">>>Stop listener=>GuiFunctiontestingListener");                isStarted = false;                isEnded = true;            }            if(this.isEnded){                try {//假关闭时间                    Thread.sleep(2000);                } catch (InterruptedException e) {                    e.printStackTrace();                }            long endTime = System.currentTimeMillis() - startTime;                    System.out.println(">>>listener=>GuiFunctiontestingListener stopped!Time costing:"+endTime+" ms");            }else{                System.err.println(">>>listener=>GuiFunctiontestingListener ending meet trouble!");            }        }         @Override        public int getTestingStatusCode(String status) {            // TODO Auto-generated method stub            int statusCode = 0;            switch(status){            case "Success":                statusCode = 200;                break;            case "Fail":                statusCode = 300;                break;            case "Unknown":                statusCode = 400;                default:                    break;            }            return statusCode;        }} 接口层测试状态监视器 public class InterfaceFunctiontestingListenner implements TestingListener{//这是一个Interface层的QA验证程序的状态监听器        boolean isStarted = false;        boolean isEnded = false;        @Override        public void startListener() {            // TODO Auto-generated method stub            long startTime = System.currentTimeMillis();            if(isStarted == false){                System.out.println(">>>Start listener=>InterfaceFunctiontestingListenner");                isStarted = true;                isEnded = false;            }            if(this.isStarted){                try {//假启动时间                    Thread.sleep(3000);                } catch (InterruptedException e) {                    e.printStackTrace();                }            long endTime = System.currentTimeMillis() - startTime;                    System.out.println(">>>listener=>InterfaceFunctiontestingListenner started!Time costing:"+endTime+" ms");            }else{                System.err.println(">>>listener=>InterfaceFunctiontestingListenner starting meet trouble!");            }        }         @Override        public void stopListener() {            // TODO Auto-generated method stub            long startTime = System.currentTimeMillis();            if(isEnded == false){                System.out.println(">>>Stop listener=>InterfaceFunctiontestingListenner");                isStarted = false;                isEnded = true;            }            if(this.isEnded){                try {//假关闭时间                    Thread.sleep(2000);                } catch (InterruptedException e) {                    e.printStackTrace();                }            long endTime = System.currentTimeMillis() - startTime;                    System.out.println(">>>listener=>InterfaceFunctiontestingListenner stopped!Time costing:"+endTime+" ms");            }else{                System.err.println(">>>listener=>InterfaceFunctiontestingListenner ending meet trouble!");            }        }         @Override        public int getTestingStatusCode(String status) {            // TODO Auto-generated method stub            int statusCode = 0;            switch(status){            case "Success":                statusCode = 200;                break;            case "Fail":                statusCode = 300;                break;            case "Unknown":                statusCode = 400;                break;                default:                    break;            }            return statusCode;        }} 数据库数据验证测试状态监视器 public class DBlevelDataValidationListener implements TestingListener{//这是一个DB层的QA验证程序的状态监听器    boolean isStarted = false;    boolean isEnded = false;    @Override    public void startListener() {        // TODO Auto-generated method stub        long startTime = System.currentTimeMillis();        if(isStarted == false){            System.out.println(">>>Start listener=>DBlevelDataValidationListener");            isStarted = true;            isEnded = false;        }        if(this.isStarted){            try {//假启动时间                Thread.sleep(3000);            } catch (InterruptedException e) {                e.printStackTrace();            }        long endTime = System.currentTimeMillis() - startTime;                System.out.println(">>>listener=>DBlevelDataValidationListener started!Time costing:"+endTime+" ms");        }else{            System.err.println(">>>listener=>DBlevelDataValidationListener starting meet trouble!");        }    }     @Override    public void stopListener() {        // TODO Auto-generated method stub        long startTime = System.currentTimeMillis();        if(isEnded == false){            System.out.println(">>>Stop listener=>DBlevelDataValidationListener");            isStarted = false;            isEnded = true;        }        if(this.isEnded){            try {//假关闭时间                Thread.sleep(2000);            } catch (InterruptedException e) {                e.printStackTrace();            }        long endTime = System.currentTimeMillis() - startTime;                System.out.println(">>>listener=>DBlevelDataValidationListener stopped!Time costing:"+endTime+" ms");        }else{            System.err.println(">>>listener=>DBlevelDataValidationListener ending meet trouble!");        }    }     @Override    public int getTestingStatusCode(String status) {        // TODO Auto-generated method stub        int statusCode = 0;        switch(status){        case "Success":            statusCode = 200;            break;        case "Fail":            statusCode = 300;            break;        case "Unknown":            statusCode = 400;            break;            default:                break;        }        return statusCode;    }}
  • 创建工厂类
12345678910111213
public class FactoryClass {  public static TestingListener instanceGUIListener(){       return new GuiFunctiontestingListener();  }   public static TestingListener instanceInterfaceListener(){       return new InterfaceFunctiontestingListener();  }   public static TestingListener instanceDBListener(){       return new DBlevelDataValidationListener();  }}

以上步骤全部类似于之前设计模式中工厂模式的定义。

  • 下面写一个利用JAVA反射机制来获取工厂类的函数信息的测试类(重点)

Demo code

1234567891011121314151617181920212223242526272829
import java.lang.reflect.Method;public class ShowFunctions {//获取指定类的所有函数信息String className;//简单的JAVA POJO模式,这种Getter,Setter经常被应用在JAVA的代码中,用于对类变量进行变量的交换和传递  private String getClassName() {    return className;  }  private void setClassName(String className) {    this.className = className;  }   ShowFunctions(String className){    setClassName(className);  try {    Class<?> cluzz = Class.forName(getClassName());    if(cluzz != null){//此种方法会获取public及非public的任何已定义的函数      Method methods[] = cluzz.getDeclaredMethods();      System.out.println("[INFO]Totally got "+methods.length+" methods in CLASS named "+ getClassName());      for(Method realMethod:methods){        System.out.println("[INFO]Method info: "+realMethod.toString());      }  }    } catch (ClassNotFoundException e) {      e.printStackTrace();    }  }}
  • 测试一下

Test Code

1234567
public class TestShowFunctions {    public static void main(String[] args) {        String className = "FactoryClass";//获取类名为FactoryClass下定义的全部方法信息                new ShowFunctions(className);    }}
  • 运行结果

[INFO]Totally got 3 methods in CLASS named FactoryClass
[INFO]Method info: public static TestingListener FactoryClass.instanceGUIListener()
[INFO]Method info: public static TestingListener FactoryClass.instanceInterfaceListener()
[INFO]Method info: public static TestingListener FactoryClass.instanceDBListener()

  • 接下来通过JAVA反射机制实现一个动态执行测试Lisener的执行器,简单的一个例子,当然大多数网上的实例都是通过invoke()方法来实现的,这里没有这么实现,只是利用反射机制获取了方法名,再调用工厂模式的工厂类中实例化的对象,进而完成进一步的方法执行。

Demo Code
伪监听器执行器

123456789101112131415161718192021222324252627282930313233343536373839404142
import java.lang.reflect.Method; public class ListenerExecutor {  ListenerExecutor(String instanceName,String status){  try {    TestingListener listener = null;    Class<?> cluzz = Class.forName("FactoryClass");    try {      Method executedMethod = cluzz.getDeclaredMethod(instanceName);      String methodName = executedMethod.getName();      if(listener == null){        if(methodName.equals("instanceGUIListener")){        listener = FactoryClass.instanceGUIListener();        listener.startListener();        int statusCode = listener.getTestingStatusCode(status);        System.out.println("Status Code: "+statusCode);        listener.stopListener();    }    if(methodName.equals("instanceInterfaceListener")){      listener = FactoryClass.instanceInterfaceListener();      listener.startListener();      int statusCode = listener.getTestingStatusCode(status);      System.out.println("Status Code: "+statusCode);      listener.stopListener();    }    if(methodName.equals("instanceDBListener")){      listener = FactoryClass.instanceInterfaceListener();      listener.startListener();      int statusCode = listener.getTestingStatusCode(status);      System.out.println("Status Code: "+statusCode);      listener.stopListener();    }  }} catch (NoSuchMethodException e) {   e.printStackTrace();} catch (SecurityException e) {   e.printStackTrace();}} catch (ClassNotFoundException e) {   e.printStackTrace(); }}}
  • 测试一下

Demo Code

123456789101112
public class TestListenerExecutor {private static String s_SUCCESS = "Success";private static String s_FAIL = "Fail";private static String s_UNKNOWN = "Unknown"; public static void main(String[] args) {new ListenerExecutor("instanceGUIListener",s_SUCCESS);new ListenerExecutor("instanceInterfaceListener",s_FAIL);new ListenerExecutor("instanceDBListener",s_UNKNOWN);} }
  • 运行结果

>>>Start listener=>GuiFunctiontestingListener
>>>listener=>GuiFunctiontestingListener started!Time costing:2999 ms
Status Code: 200
>>>Stop listener=>GuiFunctiontestingListener
>>>listener=>GuiFunctiontestingListener stopped!Time costing:2003 ms
>>>Start listener=>InterfaceFunctiontestingListenner
>>>listener=>InterfaceFunctiontestingListenner started!Time costing:3001 ms
Status Code: 300
>>>Stop listener=>InterfaceFunctiontestingListenner
>>>listener=>InterfaceFunctiontestingListenner stopped!Time costing:2001 ms
>>>Start listener=>InterfaceFunctiontestingListenner
>>>listener=>InterfaceFunctiontestingListenner started!Time costing:3001 ms
Status Code: 400
>>>Stop listener=>InterfaceFunctiontestingListenner
>>>listener=>InterfaceFunctiontestingListenner stopped!Time costing:2001 ms

好了,今天就先给各位测友介绍到这里,例子的应用很简单,实现了一个假的测试状态监听器,使用一个独立的Executor去执行,实例化方法的选择完全通过JAVA的反射机制来动态获取方法名,这样做的好处大家应该能感受的到,那就是少了很多的HardCode而多了一些灵活与开放,实际上绝大多数的JAVA框架都或多或少的采取了JAVA的这个特点,来使得他们的框架的开放性更强,更容易被拓展,下次如果笔者还是在面试中被问到了这个话题,相信便不会捉襟见肘了,但是我最后还是不得不强调一下,知道这些东西也许是一个附加值,但绝对不是一个测试工程师的核心竞争力,事实上我们不需要去说一堆别人听不懂的东西来彰显自己的能力,能解决问题吗?这才是重点。

0 0
原创粉丝点击