• [java学习] java_反射机制


    摘自http://baike.baidu.com/view/3454964.htm#5

    反射是指一类应用,它们能够自描述和自控制。也就是说,这类应用通过采用某种机制来实现对自己行为的描述(self-representation)和监测(examination),并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义。

    Java中,反射是一种强大的工具。它使您能够创建灵活的代码,这些代码可以在运行时装配,无需在组件之间进行源代表链接。反射允许我们在编写与执行时,使我们的程序代码能够接入装载到JVM中的类的内部信息,而不是源代码中选定的类协作的代码。这使反射成为构建灵活的应用的主要工具。但需注意的是:如果使用不当,反射的成本很高。

    最近在成都写一个移动增值项目,俺负责后台server端。功能很简单,手机用户通过GPRS打开Socket与服务器连接,我则根据用户传过来的数据做出响应。做过类似项目的兄弟一定都知道,首先需要定义一个类似于MSNP的通讯协议,不过今天的话题是如何把这个系统设计得具有高度的扩展性。由于这个项目本身没有进行过较为完善的客户沟通和需求分析,所以以后肯定会有很多功能上的扩展,通讯协议肯定会越来越庞大,而我作为一个不那么勤快的人,当然不想以后再去修改写好的程序,所以这个项目是实践面向对象设计的好机会。

     

      首先定义一个接口来隔离类:

     

      package org.bromon.reflect;

     

      public interface Operator{

     

      public java.util.List act(java.util.List params)

     

      }

     

      根据设计模式的原理,我们可以为不同的功能编写不同的类,每个类都继承Operator接口,客户端只需要针对Operator接口编程就可以避免很多麻烦。比如这个类:

     

      package org.bromon.reflect.*;

     

      public class Success implements Operator{

     

      public java.util.List act(java.util.List params){

     

      List result=new ArrayList();

     

      result.add(new String(“操作成功”));

     

      return result;

     

      } } 我们还可以写其他很多类,但是有个问题,接口是无法实例化的,我们必须手动控制具体实例化哪个类,这很不爽,如果能够向应用程序传递一个参数,让自己去选择实例化一个类,执行它的act方法,那我们的工作就轻松多了。

     

      很幸运,我使用的是Java,只有Java才提供这样的反射机制,或者说内省机制,可以实现我们的无理要求。编写一个配置文件emp.properties:

     

      #成功响应

     

      1000=Success

     

      #向客户发送普通文本消息

     

      2000=Load

     

      #客户向服务器发送普通文本消息

     

      3000=Store

     

      文件中的键名是客户将发给我的消息头,客户发送1000给我,那么我就执行Success类的act方法,类似的如果发送2000给我,那就执行Load类的act方法,这样一来系统就完全符合开闭原则了,如果要添加新的功能,完全不需要修改已有代码,只需要在配置文件中添加对应规则,然后编写新的类,实现act方法就ok,即使我弃这个项目而去,它将来也可以很好的扩展。这样的系统具备了非常良好的扩展性和可插入性。 下面这个例子体现了动态加载的功能,程序在执行过程中才知道应该实例化哪个类:

     

      package org.bromon.reflect.*;

     

      import java.lang.reflect.*;

     

      public class TestReflect{

     

      //加载配置文件,查询消息头对应的类名

     

      private String loadProtocal(String header){

     

      String result=null;

     

      try{

     

      Properties prop=new Properties();

     

      FileInputStream fis=new FileInputStream("emp.properties");

     

      prop.load(fis);

     

      result=prop.getProperty(header);

     

      fis.close();

     

      }catch(Exception e){

     

      System.out.println(e);

     

      }

     

      return result; }

     

      //针对消息作出响应,利用反射导入对应的类

     

      public String response(String header,String content) {

     

      String result=null; String s=null;

     

      try {

     

      /* * 导入属性文件emp.properties,查询header所对应的类的名字

     

      * 通过反射机制动态加载匹配的类,所有的类都被Operator接口隔离

     

      * 可以通过修改属性文件、添加新的类(继承MsgOperator接口)来扩展协议

     

      */

     

      s="org.bromon.reflect."+this.loadProtocal(header);

     

      //加载类 Class c=Class.forName(s);

     

      //创建类的事例

     

      Operator mo=(Operator)c.newInstance();

     

      //构造参数列表

     

      Class params[]=new Class[1];

     

      params[0]=Class.forName("java.util.List");

     

      //查询act方法

     

      Method m=c.getMethod("act",params);

     

      Object args[]=new Object[1];

     

      args[0]=content;

     

      //调用方法并且获得返回

     

      Object returnObject=m.invoke(mo,args);

     

      }catch(Exception e){

     

      System.out.println("Handler-response:"+e);

     

      }

     

      return result;

     

      }

     

      public static void main(String args[]){

     

      TestReflect tr=new TestReflect(); tr.response(args[0],”消息内容”);

     

      } }

     

      测试一下:java TestReflect 1000 这个程序是针对Operator编程的,所以无需做任何修改,直接提供Load和Store类,就可以支持2000、3000做参数的调用。

     

      有了这样的内省机制,可以把接口的作用发挥到极至,设计模式也更能体现出威力,而不仅仅供我们饭后闲聊。

  • 相关阅读:
    Codeforces Round #365 Div.2
    Codeforces Round #363 Div.2[111110]
    花花的礼物 (huahua)
    FOI2019算法冬令营D1
    树(tree)
    noip2018
    1972: 最短路(shortest)
    2462: 收集(collecting)
    1282: 排列计数 perm
    1425: 数列(seq)
  • 原文地址:https://www.cnblogs.com/wanping/p/2446273.html
Copyright © 2020-2023  润新知