Java 获取继承您的第三方类的实例

Java 获取继承您的第三方类的实例,java,oop,inheritance,Java,Oop,Inheritance,所以情况是这样的:我正在创建一个多人游戏,我希望我的朋友能够为它创建机器人。所以我要做的是创建一个抽象类Bot{},为Bot定义函数,然后它们必须实现它们:非常简单 我陷入困境的地方是,如何在之后添加它们?您可以使用反射或类似的方法来查找Bot的所有继承者吗?或者我需要搜索.jar文件吗 到目前为止,我是这样做的(简化了,类不在同一个文件中,等等): 然后当我需要每个机器人中的一个时: ArrayList<Bot> bots = new ArrayList<>(); bo

所以情况是这样的:我正在创建一个多人游戏,我希望我的朋友能够为它创建机器人。所以我要做的是创建一个
抽象类Bot{}
,为Bot定义函数,然后它们必须实现它们:非常简单

我陷入困境的地方是,如何在之后添加它们?您可以使用反射或类似的方法来查找
Bot
的所有继承者吗?或者我需要搜索.jar文件吗

到目前为止,我是这样做的(简化了,类不在同一个文件中,等等):

然后当我需要每个机器人中的一个时:

ArrayList<Bot> bots = new ArrayList<>();
bots.add(new Bot1());
//...
ArrayList bots=new ArrayList();
添加(新的Bot1());
//...
我的问题是,如果我要使用它,因为
Bot1
实例是硬编码的,我需要允许人们修改我的代码来添加他们自己的机器人程序,这是我不想要的

我的问题是,我如何在没有硬编码的情况下实现这一点?我知道这是可能的,就像Minecraft做的那样(mods之类的),但我不知道怎么做。到目前为止,我的研究没有得到任何结果(可能是因为我不知道如何用一句简单的话来解释这一点……),所以欢迎提供任何提示,以及学习如何做的地方


此外,我对OOP等有很好的理解,但我对反射和
getClass()
事物完全陌生…

从我在本主题中所读到的内容来看,除了在检查每个类是否是Bot的子类的同时通过“蛮力”遍历每个类之外,似乎没有其他真正的方法


要回答您的问题,这是可能的,并且在上述主题中进行了描述

如果您使用的是Spring,您可以请求用@Component注释Bot实现,以便您的应用程序可以使用组件扫描,然后使用
@Autowired private List Bot访问它们。

这可能不是您要求的,但在运行时尝试计算给定类的所有子类在我看来不是一个好主意。 为什么不为您的朋友提供注册他们的
Bot
实例的便利,就像他们希望通过singleton注册的那样:

public enum BotHolder {
    BOTS;

    private final List<Bot> bots = new ArrayList<>();

    public void registerBot(Bot bot) {
        bots.add(bot);
    }

    public List<Bot> get() {
        return bots;
    }
}
公共枚举BotHolder{
机器人;
私有最终列表bots=new ArrayList();
公共无效登记点(Bot){
添加(bot);
}
公共列表get(){
返回机器人;
}
}
最简单的方法(没有任何外部框架)可能是将
Bot
定义为一个接口(,服务提供商接口),然后使用JRE附带的内置机制。然后需要部署自定义的
Bot
实现(作为jar),以便可以在应用程序的类路径上访问它们

比如说:

SPI合同:

public interface Bot {
    int play();
}
实现(这需要打包到一个JAR中,该JAR具有链接文档中指定的目录结构,包括
META-INF
文件夹):

查找:

import java.util.ServiceLoader;

public class BotResolver {

    private final ServiceLoader<Bot> loader;

    public BotResolver() {
        loader = ServiceLoader.load(Bot.class);
    }

    /**
     * Gets all bot implementations that are currently available in the classpath.
     */
    public List<Bot> getAllBots() {

        List<Bot> allBots = new ArrayList<>();
        Iterator<Bot> it = loader.iterator();

        while (it.hasNext()) {
           allBots.add(it.next());
        }

        return allBots;
    }
}
导入java.util.ServiceLoader;
公共类BotResolver{
私人最终服务装载机;
公共冲突解决程序(){
loader=ServiceLoader.load(Bot.class);
}
/**
*获取类路径中当前可用的所有bot实现。
*/
公共列表getAllBots(){
List allBots=new ArrayList();
迭代器it=loader.Iterator();
while(it.hasNext()){
allBots.add(it.next());
}
返回所有机器人程序;
}
}

米克的回答很好

下面是我的解决方案(不是使用
ServiceLoader
API,而是使用类似的方法)

  • 声明一个属性文件,其属性名
    BotClasses=
    后跟 您朋友的bot类的完全限定路径。(适用于多个 类通过一些分隔符将它们分开,如

  • 通过使用分隔符拆分属性值来迭代
    BotClasses
    属性值,然后对每个完全限定的类名使用:

  • Bot newObj=(Bot) Class.forName(strFullyQualifiedClassName).newInstance()


    只有在
    Bot
    实现中有默认的/nor arg构造函数时,这才有效。

    您可以让您的朋友创建实现您的Bot接口的Bot类,然后将它们全部放在一个文件夹中,并使用classLoader.loadClass加载文件夹中的每个类。使用instanceof检查每个类是否实现了所需的接口,如果没有,则放弃它们。
    我在本周早些时候写了一个简单的插件系统来尝试这一点,但是现在还没有访问代码,但是关于如何使用所有这些元素的信息是现成的,祝你好运

    这里有很多想法:还有:看看工厂设计模式。然后你可以使用
    reflection
    来加载类。我已经使用Netbeans不到一个月了,所以(假设Spring是@comments),我还不熟悉这个。谢谢你的提示,我很快会查的。
    public class MyBot implements Bot {
        @Override
        public int play() {
            // do something
        }
    }
    
    import java.util.ServiceLoader;
    
    public class BotResolver {
    
        private final ServiceLoader<Bot> loader;
    
        public BotResolver() {
            loader = ServiceLoader.load(Bot.class);
        }
    
        /**
         * Gets all bot implementations that are currently available in the classpath.
         */
        public List<Bot> getAllBots() {
    
            List<Bot> allBots = new ArrayList<>();
            Iterator<Bot> it = loader.iterator();
    
            while (it.hasNext()) {
               allBots.add(it.next());
            }
    
            return allBots;
        }
    }