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

时间:2013-09-07 09:48:10

标签: java interface implements

所以我正在构建一个游戏引擎,我需要能够从实现某个接口的类调用方法(我只想调用接口实现的方法)。

我的问题是我不知道类名会实现什么。

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

4 个答案:

答案 0 :(得分:2)

真的,你问的是工厂模式或依赖注入容器,比如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 :(得分:1)

如果你只想从界面调用方法(好!),那么你现在通常不需要实现者的名字。

getRunnableFromSomewhere().run();

始终有效,并在该方法返回的实例上调用run()方法。

如果您想在运行时使用类名,请在实例上调用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()方法。

答案 2 :(得分:0)

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

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

  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();
    }

}

答案 3 :(得分:0)

服务提供界面

您可以使用java SPI(服务提供程序接口),稍后实现jar会在清单中声明相同的服务。使用应用程序可以进行查找,迭代它们并选择一个。

一个例子是不同的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();