博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
利用反射实现类的动态加载
阅读量:6501 次
发布时间:2019-06-24

本文共 5923 字,大约阅读时间需要 19 分钟。

  hot3.png

//首先定义一个接口来隔离类:public interface Operator{//    public java.util.List act(java.util.List params);      public java.util.List act(String content,String content2,java.util.List params);}

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

import java.util.*;public class Success implements Operator{    public static void main(String[] args) {        List list = new ArrayList();        list.add("Success3");        Operator op = new Success();        System.out.println("act===" + op.act("Success1", "Success2", list));    }//       public java.util.List act(java.util.List params)    public java.util.List act(String content, String content2,                              java.util.List params) {        List result = new ArrayList();        result.add(content);        result.add(content2);        result.add(params);        return result;    }}

同样,也可以写另一个类:

import java.util.*;public class Load implements Operator{    public static void main(String[] args) {        List list = new ArrayList();        list.add("Load3");        Operator op = new Load();        System.out.println("act===" + op.act("Load1", "Load2", list));    }//       public java.util.List act(java.util.List params)    public java.util.List act(String content, String content2,                              java.util.List params)    {        List result = new ArrayList();        result.add(content);        result.add(content2);        result.add(params);        return result;    }}
我们还可以写其他很多类,但是有个问题,接口是无法实例化的,我们必须手动控制具体实例化哪个类,这很不爽,如果能够向应用程序传递一个参数,让自己去选择实例化一个类,执行它的act方法,那我们的工作就轻松多了。
 
很幸运,我使用的是Java,只有Java才提供这样的反射机制,或者说内省机制,可以实现我们的无理要求。编写一个配置文件emp.properties: 
#成功响应

1000=Success

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

2000=Load

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

3000=Store

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

下面这个例子体现了动态加载的功能,程序在执行过程中才知道应该实例化哪个类: 

import java.lang.reflect.*;import java.util.Properties;import java.io.FileInputStream;import java.util.List;//这个程序是针对Operator编程的,所以无需做任何修改,直接提供Load和Store类,就可以支持2000、3000做参数的调用//有了这样的内省机制,可以把接口的作用发挥到极至,设计模式也更能体现出威力,而不仅仅供我们饭后闲聊。public class TestReflect{       //加载配置文件,查询消息头对应的类名    private String loadProtocal(String header)    {        String result=null;       try       {           Properties prop=new Properties();//           FileInputStream fis=new FileInputStream("emp.properties");//           id = prop.getProperty(idString);//           prop.load(fis);//           fis.close();           prop.load(getTCL().getResourceAsStream("emp.properties"));           result=prop.getProperty(header);        }catch(Exception e)       {           System.out.println(e);       }        return result;    } private static ClassLoader getTCL() throws IllegalAccessException,                                            InvocationTargetException {     Method method = null;     try {         method = Thread.class.getMethod("getContextClassLoader", null);     } catch (NoSuchMethodException e) {         return null;     }     return (ClassLoader)method.invoke(Thread.currentThread(), null); }    //针对消息作出响应,利用反射导入对应的类    public String response(String header,String content,String content2,List list)    {        String result=null;        String s=null;       try       {           /*            * 导入属性文件emp.properties,查询header所对应的类的名字            * 通过反射机制动态加载匹配的类,所有的类都被Operator接口隔离            * 可以通过修改属性文件、添加新的类(继承MsgOperator接口)来扩展协议            */           s="org.bromon.reflect."+this.loadProtocal(header).trim();           //加载类           System.out.println("s==="+s);//打印 s===org.bromon.reflect.Success           Class c=Class.forName(s);//java.lang.reflect.Methods 是用来描述某个类中单个方法的一个类//           Method m[] = c.getDeclaredMethods();////           for (int i = 0; i < m.length; i++)////               System.out.println(m[i].toString());//  打印   public java.util.List org.bromon.reflect.Success.act(java.util.List)           //创建类的事例           Operator mo=(Operator)c.newInstance();           System.out.println("mo==="+mo);           //构造参数列表           Class params[]=new Class[3];//           params[0]=Class.forName("java.util.List");             params[0]=Class.forName("java.lang.String");             params[1]=Class.forName("java.lang.String");             params[2]=Class.forName("java.util.List");           System.out.println("params[0]==="+params[0]);//           //查询act方法           Method m=c.getMethod("act",params);           System.out.println("method=="+m.toString());           Object[] args=new Object[3];           args[0]=content;           args[1]=content2;           args[2]=list;//           //调用方法并且获得返回           Object returnObject=m.invoke(mo,args);//这个地方出问题了,抛异常~~~~//           System.out.println("returnObject==="+returnObject);           List result2 = (List)returnObject;           result = (String)result2.get(0);           System.out.println("result2=="+result2);//        }catch(Exception e)       {           System.out.println("Handler-response:"+e);//Handler-response:java.lang.IllegalArgumentException: argument type mismatch           //IllegalArgumentException - 如果该方法是实例方法,且指定对象参数不是声明基础方法的类或接口(或其中的子类或实现程序)的实例;           //如果实参和形参的数量不相同;如果基本参数的解包转换失败;或者如果在解包后,无法通过方法调用转换将参数值转换为相应的形参类型。       }        return result;    }    public static void main(String args[])    {        TestReflect tr=new TestReflect();          List list = new java.util.ArrayList();          list.add("测试List");          tr.response("2000","Load1","Load2",list);//1000是Success,2000是Load   tr.response("1000","Success1","Success2",list);//1000是Success,2000是Load    }}

测试一下,run一下TestReflect类,打印内容有,great!!

result2==[Load1, Load2, [测试List]]
result2==[Success1, Success2, [测试List]]

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

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

转载于:https://my.oschina.net/exit/blog/153241

你可能感兴趣的文章
跨链技术与通证经济
查看>>
爬虫学习之-xpath
查看>>
js jQuery 右键菜单 清屏
查看>>
dotConnect for Oracle
查看>>
Eclipse下C/C++开发环境搭建
查看>>
Eclipse中设置在创建新类时自动生成注释
查看>>
我的友情链接
查看>>
CoreOS 手动更新
查看>>
golang 分页
查看>>
再论机械式针对接口编程
查看>>
25 个 Linux 性能监控工具
查看>>
C#程序员整理的Unity 3D笔记(十三):Unity 3D基于组件的思想
查看>>
Tengine-2.1.1 ngx_http_concat_module 400问题
查看>>
Windows中挂载安装ISO文件
查看>>
Wayland 1.0发布
查看>>
golang的goroutine是如何实现的?
查看>>
乐视云基于Kubernetes的PaaS平台建设
查看>>
R 学习笔记《十》 R语言初学者指南--图形工具
查看>>
PHP通过读取DOM抓取信息
查看>>
DICOM医学图像处理:DICOM网络传输
查看>>