繁体   English   中英

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

[英]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描述的界面......

  1. 如果你可以使用OSGI,它就像捕捉手指一样简单! 在oSGI中,您可以拥有同一课程的多个verssions。 您所做的只是具有不同版本的相同捆绑包。

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

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

我知道唯一支持你所追求的是OSGI

替代文字

它的网络模型,在本文“ 在OSGi中公开引导类路径 ”中描述,确实允许这样做

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

请参阅本教程以了解OSGI框架的开始和选择(如EquinoxKnoplerfishApache 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM