[英]Java: Dynamically Load Multiple Versions of Same Class
我希望能够做的是加载一组类,可能都在同一个文件夹中。 所有这些都实现了相同的接口并且是同一个类,然后在我的代码中我希望能够在这些类上调用函数。
根据您对我的问题的回答,您似乎想要定义一个游戏界面,然后插入任意数量的AI实现,可能是从.properties文件配置的。 这是API接口的相当标准的使用。
您定义了一个EngineInterface,它提供了一种接受游戏状态并返回移动的方法。 然后定义所有实现EngineInterface的多个类。 您的驱动程序读取属性文件以获取实现类的名称,使用Class.forName()实例化它们并将它们存储在列表和/或映射中。 然后,当驱动程序获得请求时,它依次调用每个实现并跟踪结果。
你尝试过类似的东西:
class Move; // some data type that is able to represent the AI's move.
interface AI {
Move getMove( GameState state);
};
AIOne implements AI;
AITwo implements AI;
每个类都会实现自己的算法来生成移动,但是会被调用但是通过普通方法调用
可以用OSGI做你想做的事情,但你也可以使用自定义类加载器。 我们的想法是,您必须为要加载的类的每个版本实例化一个类加载器。 在这里你可以找到一个很好的解释。
但我认为你真正需要解决的问题是基于Jim Garrison或Dave L Delaney描述的界面......
如果你可以使用OSGI,它就像捕捉手指一样简单! 在oSGI中,您可以拥有同一课程的多个verssions。 您所做的只是具有不同版本的相同捆绑包。
否则,您仍然可以编写读取这两个类的自定义类加载器。 一种方法就是这样。 您编写了两个ClassLoader,其中一个加载了该类的一个版本,另一个加载了该类的另一个版本。 现在根据需要选择classloader1或classloader2来加载类。 所以现在你也可以在内存中同时加载同一个类的多个版本。
注意:确保这实际上是您想要做的,可能还有其他方法可以解决您的问题。
我知道唯一支持你所追求的是OSGI :
它的网络模型,在本文“ 在OSGi中公开引导类路径 ”中描述,确实允许这样做
网络模型的副作用(或目标)之一是类型隔离或类版本控制:同一类的多个版本可以在同一个VM内很好地共存,因为每个版本都加载到自己的网络中,即自己的空间。
请参阅本教程以了解OSGI框架的开始和选择(如Equinox , Knoplerfish或Apache Felix )
可以使用动态类加载来完成。 它不是加载不同版本的类,而是加载超类或接口的不同子类。
重要的步骤是:
(1)使用Class.forName(...)按名称加载类。 该类必须位于类路径中。
(2)使用aClass.newInstance()实例化对象。 如果构造函数不需要参数,这很容易。
以下代码应该为您提供一些想法。 它不处理您必须执行的异常。
class Context {
void moveUp();
void moveDown();
...
}
interface AI {
void action(Context con);
}
public class Game {
public Game() {
Context aContext = new Context();
String[] aAIClsNames = this.getAIClassNames("ai.list");
AI[] aAIs = this.loadAI(aAIClsNames);
this.run(aAIs);
}
String[] getAIClassNames(String pAIClassListFile) {
// .. Load the file containning the AI-class file names
}
AI[] loadAI(String[] pAIClsNames) {
AI[] AIs = new AI[pAIClsNames.length];
for(int i = 0; i < pAIClsNames.length; i++) {
String aAIClsName = pAIClsNames[i];
// (1) Get the class by name
Class<? extends AI> aAICls = Class.forName(aAIClsName);
// (2) Notice the cast as all of class in the list must implements AI
AIs[i] = (AI)aAICls.newInstance();
}
return AIs;
}
void run(AI[] pAIs) {
// ...
}
}
希望这可以帮助。
Jim的回答很好 - 您可以命名要使用的类,并且它们都符合通用API。 但是,给出的解决方案假定类已经在应用程序的类路径上可用。 您可能希望以后能够添加更多实现,例如在安装应用程序之后。
如果是这样,那么您可能需要使用自定义类加载器。 例如,您可以允许人们将jar文件放在某个特定文件夹中,并将实现的类名添加到属性文件中。 然后,您需要一个自定义类加载器,而不是从该文件夹中的jar加载类,并且您将使用该类加载器来加载类(例如,使用Class.forName(className,classLoader))。
实际上,如果每个jar文件都有一个类加载器,那么您将能够在jar文件中拥有多个具有相同名称的类,因为类加载器定义了类名边界。 这几乎是OSGI正在做的事情。
这里有一些与从jar加载类相关的代码:
http://sourceforge.net/projects/jcloader/ http://www.javaworld.com/javatips/jw-javatip70.html
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.