Java:动态加载同一类的多个版本

时间:2009-11-10 05:02:41

标签: java osgi classloader

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

7 个答案:

答案 0 :(得分:5)

根据您对我的问题的回答,您似乎想要定义游戏界面,然后插入任意数量的AI实现,可能是从.properties文件配置的。这是API接口的相当标准的使用。

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

答案 1 :(得分: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 :(得分:2)

可以使用OSGI执行您想要的操作,但您也可以使用自定义类加载器。我们的想法是,您必须为要加载的类的每个版本实例化一个类加载器。 Here你可以找到一个很好的解释。

但我认为你真正需要解决的问题是基于Jim Garrison或Dave L Delaney描述的界面......

答案 3 :(得分:1)

  1. 如果你可以使用OSGI,就像它一样简单 掰手指!在oSGI你可以 有多个相同的经文 类。你所做的一切都是一样的 捆绑包含不同版本。

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

  3. 注意:确保您确实想要这样做,可能还有其他方法可以解决您的问题。

答案 4 :(得分:1)

我知道的唯一支持你所追求的内容的框架是 OSGI

alt text

在本文“Exposing the boot classpath in OSGi”中描述的网络模型确实允许

  

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

请参阅此tutorial了解并开始选择OSGI框架(例如EquinoxKnoplerfishApache Felix

答案 5 :(得分: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) {
        // ...
    }
}

希望这有帮助。

答案 6 :(得分:0)

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