简体   繁体   English

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

[英]Java: Dynamically Load Multiple Versions of Same Class

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. 所有这些都实现了相同的接口并且是同一个类,然后在我的代码中我希望能够在这些类上调用函数。

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. 根据您对我的问题的回答,您似乎想要定义一个游戏界面,然后插入任意数量的AI实现,可能是从.properties文件配置的。 This is fairly standard use of an API interface. 这是API接口的相当标准的使用。

You define an EngineInterface providing a method that accepts game state and returns the move. 您定义了一个EngineInterface,它提供了一种接受游戏状态并返回移动的方法。 Then you define multiple classes that all implement EngineInterface. 然后定义所有实现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. 您的驱动程序读取属性文件以获取实现类的名称,使用Class.forName()实例化它们并将它们存储在列表和/或映射中。 Then when the driver gets requests it invokes each implementation in turn and keeps track of the results. 然后,当驱动程序获得请求时,它依次调用每个实现并跟踪结果。

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 每个类都会实现自己的算法来生成移动,但是会被调用但是通过普通方法调用

It is possible to do what you want with OSGI but you could as well use a custom classloader. 可以用OSGI做你想做的事情,但你也可以使用自定义类加载器。 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... 但我认为你真正需要解决的问题是基于Jim Garrison或Dave L Delaney描述的界面......

  1. If you can use OSGI, its as simple as snapping a finger! 如果你可以使用OSGI,它就像捕捉手指一样简单! In oSGI you can have multiple verssions of the same class. 在oSGI中,您可以拥有同一课程的多个verssions。 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. 您编写了两个ClassLoader,其中一个加载了该类的一个版本,另一个加载了该类的另一个版本。 Now based on the need you choose the classloader1 or classloader2 to load the class. 现在根据需要选择classloader1或classloader2来加载类。 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. 注意:确保这实际上是您想要做的,可能还有其他方法可以解决您的问题。

The only framework I know which does support what you are after is OSGI : 我知道唯一支持你所追求的是OSGI

替代文字

Its network model, described in this article " Exposing the boot classpath in OSGi ", does allow that 它的网络模型,在本文“ 在OSGi中公开引导类路径 ”中描述,确实允许这样做

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

See this tutorial for beginning and choose on eof the OSGI Framework (like Equinox , Knoplerfish or Apache Felix ) 请参阅本教程以了解OSGI框架的开始和选择(如EquinoxKnoplerfishApache Felix

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. (1)使用Class.forName(...)按名称加载类。 The class must be in the class path. 该类必须位于类路径中。

(2) Use aClass.newInstance() to instantiate the object. (2)使用aClass.newInstance()实例化对象。 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. 希望这可以帮助。

Jim's response is good - you name the classes you want to use, and they all conform to a common API. Jim的回答很好 - 您可以命名要使用的类,并且它们都符合通用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, eg 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. 例如,您可以允许人们将jar文件放在某个特定文件夹中,并将实现的类名添加到属性文件中。 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 (eg using Class.forName(className, classLoader)). 然后,您需要一个自定义类加载器,而不是从该文件夹中的jar加载类,并且您将使用该类加载器来加载类(例如,使用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. 实际上,如果每个jar文件都有一个类加载器,那么您将能够在jar文件中拥有多个具有相同名称的类,因为类加载器定义了类名边界。 This is pretty much what OSGI is doing. 这几乎是OSGI正在做的事情。

Here's some code relating to loading classes from jars: 这里有一些与从jar加载类相关的代码:

http://sourceforge.net/projects/jcloader/ http://www.javaworld.com/javatips/jw-javatip70.html 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