2009-11-10 106 views
6

我希望能够做的是加载一组类,可能都在同一个文件夹中。所有这些实现相同的接口,并且是相同的类,然后在我的代码中,我希望能够在这些类上调用函数。Java:动态加载同一类的多个版本

+0

这是不可能不玩游戏的自定义类加载器(甚至可能不可能)。也许如果你解释了你想要完成的事情,你会得到更多的帮助。 – 2009-11-10 05:07:15

+0

OSGI看起来很有趣,但也许我错误地接近了这个问题。 从一般意义上讲,这是我试图完成的。我有一个运行游戏机制的游戏Oware的外壳。它要求其他班级通过向他们发送游戏状态并返回一个动作来进行动作。 我想有认可各自包含不同的代码的文件夹中,可能有许多这样的。然后shell将在所有找到的AI上运行循环赛,并输出哪些AI根据哪个AI获胜。 – JonLeah 2009-11-10 05:23:08

回答

5

选择,看来你要定义一个游戏界面,然后插入在许多AI实现中,可能由.properties文件配置。这是API接口的相当标准的用法。

您定义了一个EngineInterface,它提供了一种接受游戏状态并返回移动的方法。然后定义所有实现EngineInterface的多个类。您的驱动程序读取属性文件以获取实现类的名称,使用Class.forName()将它们实例化并将它们存储在列表和/或映射中。然后,当驱动程序获取请求时,它会依次调用每个实现并跟踪结果。

1
  1. 如果你可以使用OSGI,它的那样简单 抢购手指!在oSGI中,您可以使用 具有相同的 类的多个版本。你所做的是有相同的 与不同版本的捆绑。

  2. 否则,您仍然可以编写自定义类加载器来读取这两个类。一种做法就是这样。您编写两个ClassLoaders,其中一个加载一个类的版本,另一个加载该类的另一个版本。现在根据需要选择classloader1或classloader2来加载类。所以现在你可以在内存中同时加载同一个类的多个版本。

注:确保这其实你想要做的是,有可能是在你的问题来的其他方式。

+0

我可以拥有osgi吗? – 2009-11-10 05:08:50

+0

@jason ......我没听懂你:) – 2009-11-10 06:27:46

+5

“那样简单抢购手指” ......这是关于OSGi的一个大胆的声明。 – Thilo 2009-11-11 03:32:31

1

我知道它不支持你是什么后OSGI的唯一框架:

alt text http://blog.springsource.com/wp-content/uploads/2009/01/network.png

它的网络模型,本文 “Exposing the boot classpath in OSGi” 中所描述的,并允许

网络模型的一个副作用(或目标)是类型隔离或类版本控制:相同类的多个版本可以很好地共存于同一个VM中,因为ea一个是加载到自己的网络,自己的空间。

看到这个tutorial的开始和EOF OSGi框架(如EquinoxKnoplerfishApache Felix)根据你回答我的问题

2

你有没有尝试过这样的:

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; 

每个类将实施其自己的算法生成一个举动,但会被调用,但通过常用的方法称为

2

它可以做你想做的与OSGI,但你可以使用自定义类加载器。这个想法是,你必须为要加载的每个类的版本创建一个类加载器。Here你可以找到一个很好的解释。

但我觉得你真正需要解决你的问题是基于接口,如由吉姆·加里森和戴夫大号德莱尼描述的东西...

0

它可以使用动态类加载来完成。它不是加载不同版本的类,而是加载超类或接口的不同子类。

最重要的步骤是:

(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) { 
     // ... 
    } 
} 

希望这会有所帮助。

0

Jim的回复非常好 - 您将要使用的类命名,并且它们都符合通用API。然而,给出的解决方案假定类已经在应用程序的类路径中可用。您可能希望能够在稍后添加更多实现,例如应用程序安装后。

如果是这样的话,那么你可能需要使用自定义类加载器。例如,您可以允许用户将jar文件放在特定文件夹的某处,并将实现的类名添加到属性文件中。然后,您需要一个自定义类加载器,而不是从该文件夹内的jar中加载类,并且您将使用该类加载器加载类(例如,使用Class.forName(className,classLoader))。

事实上,如果你有每个jar文件一个类加载器,你就可以有多个类与整个jar文件相同的名称,如类加载器定义的类名边界。这几乎是OSGI正在做的。

下面是从罐子与加载类的一些代码:

http://sourceforge.net/projects/jcloader/ http://www.javaworld.com/javatips/jw-javatip70.html