如何调用List中某些对象实现的特定接口? Java的

时间:2017-05-20 10:30:06

标签: java list generics interface instanceof

假设我有一个基本的动物类

abstract class Animal {
// basic animal code
}

现在我有两种不同的动物......

public class Dog extends Animal{
// dog code
}

public class Bird extends Animal implements Flyable{

    // bird code
    @Override
    public void fly() {
        System.out.println("flap flap");
    }

}

Flyable是一个简单的界面,它包含一个方法:

public void fly();

如果我有一个动物清单,我想循环通过它,告诉鸟类飞行但是只留下狗,我怎么能实现这个目标呢?

public class Test {

    public static List<Animal> animals = new ArrayList<Animal>();

    public static void main(String[] args) {
        animals.add(new Bird("flop"));
        animals.add(new Dog("plop"));

        for(Fly f : animals) { // exception here because of mismatch of types
            f.flap();
        }

    }

}

到目前为止,我发现的唯一选项是使用instanceof来确定一个类是否实现了Flyable接口,但是快速谷歌搜索表明这对业务不利。 来源如: https://www.quora.com/Is-using-instanceof-in-Java-consider-bad-practice-Any-alternative-to-using-this-keyword 将instanceof的使用视为糟糕的设计。

我觉得有一种直观的方式可以做到这一点,我以前见过,但找不到一个好的解决方案。

4 个答案:

答案 0 :(得分:2)

  

Flyable是一个简单的界面,它包含一个方法:

public void fly();

我认为这是一个错字,因为您调用的方法名为flap而不是fly

您可以使用instanceof关键字来检查是否有类is-a超类。

for(Animal animal : animals) { // loop through all animals
    if(animal instanceof Flyable) { // if that animal IS-A Flyable (so it can fly)
        ((Flyable) animal).flap(); // cast to Flyable and let it fly!
    }
}
  

我到目前为止找到的唯一选项是使用instanceof来确定一个类是否实现了Flyable接口,但是快速谷歌搜索表明这对业务不利

在我看来,这一点都不差。而且这是完成任务的唯一方法。

答案 1 :(得分:1)

当您在Flyable类中实现包含fly()方法声明的Animal接口时,您只需定义动物的每个子类都具有飞行能力。

在我看来,使用instanceof是一种不好的做法,因为它使代码非常混乱:一方面,Dog有一个fly()实现(它通过Animal类间接实现Flyable接口) ,另一方面,当您在接口实例上调用fly()时,不会调用它。

你至少有两种方法可以阻止Dog拥有飞行能力,这是我的两个最爱:

  1. 您可以创建2个类FlyingAnimalNonFlyingAnimal,它们都扩展Animal类,而FlyingAnimal类实现Flyable接口和{{1没有。 Bird将扩展NonFlyingAnimal类,而Dog将扩展FlyingAnimal类。 通过这种方式,您可以创建NonFlyingAnimal列表,迭代它,并在每个飞行成员上调用FlyingAnimal方法(狗不是其中之一)。

  2. 使用策略设计模式:

  3. fly()

    通过这种方式,您可以为public interface Flyable { String fly(); } class ItFlys implements Flyable { public String fly() { return "I can fly"; } } class CantFly implements Flyable { public String fly() { return "I can't fly"; } } public class Animal { private String name; private double height; private int weight; private String favFood; private double speed; private String sound; public Flyable flyingType; public String tryToFly() { return flyingType.fly(); } public void setFlyingAbility(Flyable newFlyType) { flyingType = newFlyType; } } public class Bird extends Animal{ public Bird() { super(); flyingType = new ItFlys(); } } public class Dog extends Animal{ public Dog() { super(); flyingType = new CantFly(); } } 的每个子类设置一个飞行类型。 当您在Animal课程中调用fly()方法时,您将获得“非飞行动物”行为。

答案 2 :(得分:0)

另一种方法是组织您的对象,这样您就不必检查每个对象以确定如何处理它。例如,您可以维护一个Animal类,其中包含Flyable的各种集合,包括{{1}}集合。迭代Flyable集合不需要测试每个实例是否为Flyable。如果你有其他只运行Flyable对象的类,它们也不必测试每个成员,从而导致代码更清晰,工作量更少。

答案 3 :(得分:0)

您可以使用几种可能性:

  1. fly()作为抽象方法放在基类中。让Dog的实施方案抛出CannotFlyException,或以其他方式实施一些非飞行的&#34;行为。然后使用

    迭代List<Animal>
    try {
        animal.fly();
    catch (CannotFlyException() cfe) {
        System.out.println("grounded!");
    }
    
  2. 为您的Animal()类提供一个列出支持的操作的抽象方法,然后测试每个成员以查看它是否实现了fly()方法:

    public abstract class Animal {
        private Set<String> behaviors;
    
        public Animal() {
            behaviors = new HashSet<String>();
        }
    
        public Set<String> getBehaviors() {
            return behaviors;
        }
    }
    
    public class Dog extends Animal {
        public Dog() {
            super();
            behaviors.add("fetch");
        }
    
        public String fetch(String fetched) {
            return "Dog fetched " + fetched;
        }     
    }
    
    public class Bird extends Animal implements Flyable {
        public Dog() {
            super();
            behaviors.add("fly");
        }
    
        @Override
        public String fly() {
            return "flap flap";
        }     
    }
    
    ....
    
    List<Animal> animals = MagicalAnimalListCreator.MakeAnimalList();
    for (Animal animal : animals) {
        if (animal.getBehaviors().contains("fly")) {
            animal.fly();
        }
    }
    
  3. 您可以按照目前的方式进行操作,但是然后尝试将列表中的每个成员投射到Bird并在尝试飞行前抓住ClassCastException。如果演员阵容成功,你就有了一只小鸟并可以飞行。