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

发布于 2024-08-10 14:06:06 字数 74 浏览 4 评论 0 原文

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

What I'd like to be able to do is to load set of classes, probably all in the same folder. All of which implement the same interface and are the same class, then in my code I'd like to be able to call functions on those classes.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

雪若未夕 2024-08-17 14:06:07

我知道唯一支持您所追求的框架是 OSGI:

 alt text

它的网络模型,在这篇文章中描述“在 OSGi 中公开启动类路径”,确实允许

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

请参阅此教程开始并选择 OSGI 框架(例如 春分KnoplerfishApache Felix

The only framework I know which does support what you are after is OSGI:

alt text

Its network model, described in this article "Exposing the boot classpath in OSGi", does allow that

One of the side effects (or aims) of the networking model is type isolation or class versioning: multiple version of the same class can coexist nicely inside the same VM since each one is loaded into its own network, its own space.

See this tutorial for beginning and choose on eof the OSGI Framework (like Equinox, Knoplerfish or Apache Felix)

情深缘浅 2024-08-17 14:06:07

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

重要的步骤是:

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

希望这有帮助。

It can be done using dynamic class loading. It is not loading class of different version but different sub-classes of a super class or interface.

The important steps are:

(1) Use Class.forName(...) to load a class by name. The class must be in the class path.

(2) Use aClass.newInstance() to instantiate the object. This is easy if there is no parameter needed for the constructor.

The following code should provide some idea for you. It does not handle exception which you have to do it.

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

Hope this helps.

百合的盛世恋 2024-08-17 14:06:07

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

Jim's response is good - you name the classes you want to use, and they all conform to a common API. However the solution given assumes the classes are all available on the classpath of the application already. You may be wanting to be able to add more implementations later, e.g. after the application is installed.

If thats the case, then you'll probably need to use a custom classloader. For example, you could allow people to put jar files inside a particular folder somewhere, and to add the class names of the implementations to a properties file. You would then need a custom classloader than can load classes from the jars inside that folder, and you would use that classloader to load the classes (e.g. using Class.forName(className, classLoader)).

In fact if you have a classloader per jar file, you will be able to have multiple classes with the same names across the jar files, as the classloader defines the class name boundaries. This is pretty much what OSGI is doing.

Here's some code relating to loading classes from jars:

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

黯然#的苍凉 2024-08-17 14:06:06

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

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

Based on your answer to my question, it seems you want to define a game interface and then plug in any number of AI implementations, probably configured from a .properties file. This is fairly standard use of an API interface.

You define an EngineInterface providing a method that accepts game state and returns the move. Then you define multiple classes that all implement EngineInterface. Your driver reads a property file to get the names of the implementation classes, instantiates them with Class.forName() and stores them in a list and/or map. Then when the driver gets requests it invokes each implementation in turn and keeps track of the results.

空心↖ 2024-08-17 14:06:06

您是否尝试过类似的操作:

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;

每个类都会实现自己的算法来生成移动,但会被调用但由通用方法调用

Have you tried something like:

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;

Each class would implement its own algorithm for generating a move, but would be called but called by common method

乖乖兔^ω^ 2024-08-17 14:06:06

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

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

It is possible to do what you want with OSGI but you could as well use a custom classloader. The idea is that you have to instanciate a classloader for every version of the class you want to load. Here you can find a good explanation.

But I think what you really need to solve your problem is something based on interfaces like described by Jim Garrison or Dave L Delaney...

心的憧憬 2024-08-17 14:06:06
  1. 如果你会使用OSGI,那就简单了
    打响指!在 oSGI 中你可以
    有多个相同版本
    班级。你所做的就是拥有相同的
    具有不同版本的捆绑包。

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

注意:确保这确实是您想要执行的操作,可能还有其他方法可以解决您的问题。

  1. If you can use OSGI, its as simple as
    snapping a finger! In oSGI you can
    have multiple verssions of the same
    class. All you do is have same
    bundles with different versions.

  2. Otherwise you can still write your custom class loader that reads both the classes. One way of doing it would be like this. You write two ClassLoaders, one of them loads one version of the class and the other loads the other version of the class. Now based on the need you choose the classloader1 or classloader2 to load the class. So now you can also have multiple versions of the same class loaded simultaneously in the memory.

Note: Make sure this is actually you want to do, there may be other ways of coming around your problem.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文