Java动态加载类
来源:互联网 发布:汝知其劳逸不 编辑:程序博客网 时间:2024/04/29 08:12
Java动态加载类的意义和目的:
Java动态加载类主要是为了不改变主程序代码,通过修改配置文件就可以操作不同的对象执行不同的功能。主要有利于系统的扩展,例如当我要改变一个功能,只需要做一个类,然后编写相应的功能,通过配置文件就可以使用新的功能,不需要修改系统的任何地方,只需要添加一个类;充分实现了松散耦合。满足了开闭原则(对修改关闭,对添加或删除开放);
动态加载类设计模式
几个重要概念
Interface(接口):定义了一堆未实现的方法(即抽象方法);它们的具体实现是由要实现这个接口的类来实现方法的具体功能。
Class.forName(String className): 将一个给定的字符串通过forName方法转换成一个类类型,例如:Class.forName(“Integer”)他就能产生一个Integer类型;通过newInstance()方法可以产生该类的对象。例如ArrayList arr=(ArrayList)Class.forName(“ArrayList”).newInstance()
就产生了一个ArrayList的对象arr,通过它就可以调用ArrayList类的方法。注意:className 对应的字符串的类必须有一个无参的构造方法。
Java动态加载类的实现过程(造汽车为例)
1. 创建一个接口(ICarFactory),他有一个未实现的方法makeCar()用于制造汽车。
2. 有两个类实现了ICarFactory接口,那么他们也实现了makeCar()方法。
BYDFactroy类----------------makeCar()用于制造BYD,他实现了具体的制造BYD的方法
BMWFactroy类--------------makeCar()用于制造BMW,他实现了具体制造BMW的方法
3. 创建配置文件xml将相应的类名(类全名=包名+类名)写入相应的位置;
4. 创建主程序类,首先声明一个ICarFactory类型的变量icf,然后从xml中读出相应的类名,调用Class.forName(className).instance()得到具体类的实例并赋值给icf,最后通过icf调用makeCar()方法,就可以得到一辆造好的汽车。
注意:该实验用到的JAR包为dom4j-1.6.1.jar,当然你也可以从property里读或者直接用java解析xml的类这样你就不需要这个外部JAR包了。
创建接口
package dynamic.test;
//接口 用于知道汽车 有一个抽象方法makeCar();实现他的类都要实现该方法
public interface ICarFactory {
public void makeCar();//等待实现的造车方法
}
创建两个实现了接口的类
//创建BYDFactory类,实现了ICarFactory
package dynamic.test;
public class BYDFactory implements ICarFactory {
//实现了ICarFactory的makeCar()方法
public void makeCar() {
System.out.println("BYDFactroy made a BYD for you");
}
}
//创建BMWFactory类,实现了ICarFactory
package dynamic.test;
public class BMWFactory implements ICarFactory {
//实现了ICarFactory的makeCar()方法
public void makeCar() {
System.out.println("BMWFactroy made a BMW for you");
}
}
创建配置文件Factory.xml
<Factory>
<!--相应的造车工厂的类全名,现在的程序可以选dynamic.test.BMWFactory或dynamic.test.BYDFactory -->
<Factroy-Name>dynamic.test.BYDFactory</Factroy-Name>
</Factory>
创建测试程序主类
package dynamic.test;
import java.io.File;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
public class TestMain {
//测试程序主类;
public static void main(String[] args){
// 声明接口ICarFactory类型的变量icf
ICarFactory icf=null;
try {
//读xml可参照读写xml的小实验
File file=new File("lib/Factory.xml");
SAXReader reader=new SAXReader();
Document doc=reader.read(file);
Element root=doc.getRootElement();
String className=root.elementText("Factroy-Name");
//通过className得到相应的类和类实例,并将其赋给icf;必须确保className
//对应的类有一个无参构造方法
icf=(ICarFactory) Class.forName(className).newInstance();
//制造相应的汽车
icf.makeCar();
//处理异常
} catch (DocumentException e) {
// TODO Auto-generated catch block
System.out.println("找不到该文件...");
} catch (InstantiationException e) {
// TODO Auto-generated catch block
System.out.println("实例化失败...");
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
System.out.println("非法访问...");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
System.out.println("找不到该类...");
}
}
}
程序运行结果 (控制台输出)
BYDFactroy made a BYD for you
修改配置文件Factory.xml,将dynamic.test.BYDFactory改为dynamic.test.BMWFactory
<Factory>
<!--相应的造车工厂的类全名,现在的程序可以选dynamic.test.BMWFactory或dynamic.test.BYDFactory -->
<Factroy-Name>dynamic.test.BMWFactory</Factroy-Name>
</Factory>
再次运行程序观看结果(控制台输出)
BMWFactroy made a BMW for you
可以看到两次运行结果完全不同,并且我们并没有修改程序的任何一处,只是改了配置文件!这就是动态加载类的优势,同时它还可以减轻CPU和内存的负荷。
以下是引用的一篇文章:
最近在成都写一个移动增值项目,俺负责后台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做参数的调用。
有了这样的内省机制,可以把接口的作用发挥到极至,设计模式也更能体现出威力
- java动态加载类
- java 动态加载类
- Java 动态加载类
- java动态加载类
- Java动态类加载
- Java动态类加载
- Java动态类加载
- java动态加载类
- java 动态加载类
- JAVA动态加载类
- Java动态加载类
- java动态加载类
- 【java】动态加载类-URLClassLoader
- 类加载--- JAVA动态性
- java类的动态加载
- java之动态加载类
- java反射:动态加载类
- 动态编译 Java 文件 与 动态加载 Java 类
- keras入门 利用卷积神经网络进行手写数字识别
- 读锋利的jQuery(一)
- python设计模式之门面模式
- Maven加载依赖速度慢的原理和解决办法
- 【Pta基础6.3】简单求和
- Java动态加载类
- 遇到mysql表情乱码问题总结
- python(爬取大学排名)
- 数据结构实验之图论八:欧拉回路
- Java初始化过程
- verilog矩阵乘法
- iscsi:IO操作流程(三)
- PCB布线经验(转)
- [USACO1.1]黑色星期FridaytheThirteenth