Java 如何在不知道其名称的情况下调用正在实现某个接口的类?

Java 如何在不知道其名称的情况下调用正在实现某个接口的类?,java,interface,implements,Java,Interface,Implements,因此,我正在构建一个游戏引擎,我需要能够从实现特定接口的类中调用方法(我只想调用接口实现的方法) 我的问题是,我不知道实现它的类名是什么 那么,例如,Java如何在实现Runnable的所有类中调用run()方法而不知道类名呢?如果您只想从接口调用方法(很好!),那么现在通常不需要知道实现者的名称 getRunnableFromSomewhere().run(); 始终在该方法返回的实例上运行并调用run()方法 如果现在要在运行时输入类名,请在实例上simpy调用getClass().get

因此,我正在构建一个游戏引擎,我需要能够从实现特定接口的类中调用方法(我只想调用接口实现的方法)

我的问题是,我不知道实现它的类名是什么


那么,例如,Java如何在实现Runnable的所有类中调用run()方法而不知道类名呢?

如果您只想从接口调用方法(很好!),那么现在通常不需要知道实现者的名称

getRunnableFromSomewhere().run();
始终在该方法返回的实例上运行并调用
run()
方法

如果现在要在运行时输入类名,请在实例上simpy调用
getClass().getName()

System.out.println(getRunnableFromSomewhere().getClass().getName());

带有
Number
界面的简单示例:

public class NumberExample {
    public static void main(String[] args) {
        MagicNumber magic = MagicNumberProvider.get(); // a random implementation
        System.out.println(magic.getMagicNumber().doubleValue());  // We know nothing about the implementations
    }
}

class MagicNumberProvider {
    public static MagicNumber get() {
        return Math.random() > 0.5d ? new ItsMagicOne() : new ItsMagicTwo();
    }
}

interface MagicNumber {
    public Number getMagicNumber();
}

class ItsMagicOne implements MagicNumber {
    @Override
    public Number getMagicNumber() {return new Long(1);}
}

class ItsMagicTwo implements MagicNumber {
    @Override
    public Number getMagicNumber() {return new Double(2.5);}
}

它只调用接口方法,从主方法的角度来看,我们不知道使用了
MagicNumber
的哪个实现(它是随机的),并且在
Number
的哪个实现上我们实际上调用了
doubleValue()
方法。

真的,您询问的是工厂模式或依赖注入容器,如Spring

当然,您可以在接口上调用方法,问题是如何获得实例。当然,必须在某个地方进行指定、编码或配置。如果将来可能有多个配置,则最好进行配置

因此,更多的是一个真实的例子:

public interface MovementStrategy {
    public Move selectMove (Actor actor, ActorSituation theirSituation);
}

public class MonsterTypes {
    public static MonsterType GOBLIN = new MonsterType( "goblin", new AttackMover(1.2));
    public static MonsterType TROLL = new MonsterType( "troll", new AttackMover(0.45));
    public static MonsterType DEER = new MonsterType( "deer", new FleeMover(2.0));

    // useful to have, also.
    public static List<MonsterType> getAllRegisteredTypes(); 



    public static class MonsterType {
        protected String name;
        protected MovementStrategy moveStrategy;
        // TODO -- getters & setters for all properties.

        // constructor.
        public MonsterType (String name, MovementStrategy moveStrategy) {
            this.name = name;
            this.moveStrategy = moveStrategy;
        }
    }
}

public class AttackMover implements MovementStrategy {
    // SPEC: generally move towards/attack PC, with varying speeds.
}
public class FleeMover implements MovementStrategy {
    // SPEC: generally run away from PCs.
}
公共接口移动策略{
公共移动选择移动(演员-演员、演员-角色化-角色化);
}
公共类类型{
公共静态怪物类型地精=新怪物类型(“地精”,新攻击移动器(1.2));
公共静态怪物类型巨魔=新怪物类型(“巨魔”,新攻击移动器(0.45));
公共静态怪物类型鹿=新怪物类型(“鹿”,新FleeMover(2.0));
//也很有用。
公共静态列表getAllRegisteredTypes();
公共静态类类型{
受保护的字符串名称;
保护移动策略;
//TODO——所有属性的getter和setter。
//构造器。
公共类型(字符串名称、移动策略、移动策略){
this.name=名称;
this.moveStrategy=moveStrategy;
}
}
}
公共类AttackMover实现MovementStrategy{
//规格:通常以不同的速度移动到/攻击PC。
}
公共类FleeMover实现MovementStrategy{
//规格:一般从PC机上运行。
}

这可能不是一个完美的设计——它将“移动”(也称为目标寻求)与演员的轮次/动作结合在一起——但希望它能给你更多的想法。

如果我正确理解了你的问题,你似乎有点误解了多态性,你不需要知道实现接口的类型

看下面的例子,只有一个类直接知道每个敌人的类型,初始化类

  import java.util.ArrayList;
import java.util.List;

public class SO18671999 {

    public static interface Enemy {

        public void Attack(Enemy other);

        public String getName();

    }

    public static class Dragon implements Enemy {

        String name = "Onyxia";

        public void Attack(Enemy other) {
            System.out.println(this.name + " attacks " + other.getName()
                    + " for 10 dmg!");
        }

        public String getName() {
            return this.name;

        }
    }

    public static class Cerberus implements Enemy {

        private String name;
        private int dmg;

        public Cerberus(String name, int dmg) {
            this.name = name;
            this.dmg = dmg;
        }

        @Override
        public void Attack(Enemy other) {
            System.out.println(this.name + " attacks " + other.getName()
                    + " for " + this.dmg + " dmg!");
        }

        @Override
        public String getName() {
            return this.name;
        }

    }

    public static class EnemyInitializer {
        private List<Enemy> enemies;

        public EnemyInitializer() {
            enemies = new ArrayList<>();
            enemies.add(new Dragon());
            enemies.add(new Cerberus("CerberusHeadLeft", 10));
            enemies.add(new Cerberus("CerberusHeadRight", 10));
            enemies.add(new Cerberus("CerberusHeadCenter", 20));
        }

        public List<Enemy> getEnemies() {
            return enemies;
        }
    }

    public static class EnemyAttacker {
        private EnemyInitializer eI = new EnemyInitializer();

        public void startAttacking() {
            List<Enemy> enemies = eI.getEnemies();
            for (Enemy one : enemies) {
                for (Enemy two : enemies) {
                    if (one == two)
                        continue;
                    one.Attack(two);
                }
            }
        }
    }

    public static void main(String[] args) {
        EnemyAttacker eAttacker = new EnemyAttacker();
        eAttacker.startAttacking();
    }

}
import java.util.ArrayList;
导入java.util.List;
公共类SO18671999{
公共静态接口敌人{
公开无效攻击(敌方其他);
公共字符串getName();
}
公共静态类龙实现敌人{
String name=“Onyxia”;
公开无效攻击(敌方其他){
System.out.println(this.name+“attacks”+other.getName()
+“10德国马克!”;
}
公共字符串getName(){
返回此.name;
}
}
公共静态类Cerberus实现敌人{
私有字符串名称;
私有int dmg;
公共Cerberus(字符串名,int-dmg){
this.name=名称;
此值为0.dmg=dmg;
}
@凌驾
公开无效攻击(敌方其他){
System.out.println(this.name+“attacks”+other.getName()
+“对于”+this.dmg+“dmg!”);
}
@凌驾
公共字符串getName(){
返回此.name;
}
}
公共静态类EnemyInitializer{
私人名单敌人;
公共灌肠初始值设定项(){
敌人=新的ArrayList();
敌人。添加(新龙());
添加(新Cerberus(“CerberusHeadLeft”,10));
添加(新Cerberus(“CerberusHeadRight”,10));
添加(新的Cerberus(“CerberusHeadCenter”,20));
}
公共列表{
还敌;
}
}
公共静态类Enemy攻击者{
私有EnemyInitializer eI=新EnemyInitializer();
公共无效起始标记(){
列出敌人=eI.getfeeds();
为了(敌人一:敌人){
为(敌人二:敌人){
如果(一=二)
继续;
一.攻击(二);;
}
}
}
}
公共静态void main(字符串[]args){
Enemy攻击者eAttacker=新的Enemy攻击者();
eAttacker.startAttacking();
}
}
服务提供接口

您可以使用java(服务提供者接口),稍后实现的JAR通过java在清单中声明相同的服务。一个正在使用的应用程序可以进行查找、迭代并选择一个

一个例子是不同的XML解析器实现

参数

对于您的情况,有一个run方法就足够了:

class GameRunner {
    public static void mainEntry(MyGameInterface mgi) {
    }
}
而实现者可能会这样做

cöass ThirdPartyGame implements MyGameInterface {
}

GameRunner.mainEntry(new ThirdPartyGame());
带有java反射的插件

您可以使您的特定的、自定义的插件机制,并使用java反射来实例化该类。第三方jar必须放置在某个位置,即jar清单中定义的类路径中。这门课在哪里
String klazz = resBundle.getProperty("pluginClass");
Class<MyGameInterface> klazz = Cass<MyGameInterface>.forName(klazz);
MyGameInterface game = klazz.getConstructor().newInstance();