【问题标题】:What is the correct use of generics resolve this compilation error?什么是泛型的正确用法解决了这个编译错误?
【发布时间】:2012-06-27 14:35:21
【问题描述】:

重用前面的例子,想象一个动物园,其中新到的动物必须由动物园管理员“处理”(想想将它们登记到动物园)。每只动物的登记流程取决于其类别分类(哺乳动物、鸟类等)。

由于分类学类别之间的根本差异,这些过程有所不同 - 例如,鸟类有翅膀,哺乳动物有牙齿。您可能还会有一些对所有动物都适用的共享过程,但我在这里省略了它们。

代码如下:

Animal.java

public interface Animal {

    public AnimalProcessor<? extends Animal> getAnimalProcessor();
}

哺乳动物.java

public abstract class Mammal implements Animal {

    @Override
    public AnimalProcessor<Mammal> getAnimalProcessor() {

        return new MammalProcessor();
    } 

    // Specific to mammals
    public abstract int getToothCount();

}

Bird.java

public abstract class Bird implements Animal {

    @Override
    public AnimalProcessor<Bird> getAnimalProcessor() {

        return new BirdProcessor();
    }

    // Specific to birds
    public abstract float getWingspan();
}

AnimalProcessor.java

public interface AnimalProcessor<T extends Animal> {

    public void process(T critter);
}

MammalProcessor.java

public class MammalProcessor implements AnimalProcessor<Mammal> {

    @Override
    public void process(Mammal a) {
        System.out.println("Tooth count is " + a.getToothCount());
    }

}

BirdProcessor.java

public class BirdProcessor implements AnimalProcessor<Bird> {

    @Override
    public void process(Bird a) {
        System.out.print("Wingspan is " + a.getWingspan());
    }

}

獾.java

public class Badger extends Mammal {

    @Override
    public int getToothCount() {
        return 40;
    }
}

Condor.java

public class Condor extends Bird {

    @Override
    public float getWingspan() {
        return 2.9f;
    }
}

ZooKeeper.java

import java.util.List;

public class ZooKeeper {

    public void processNewAnimals(List<Animal> newcomers)
    {
        for(Animal critter : newcomers)
        {
            AnimalProcessor<? extends Animal> ap = critter.getAnimalProcessor();

                        // This line has a compilation error!
            ap.process(critter);
        }
    }
}

MainClass.java

import java.util.LinkedList;
import java.util.List;

public class MainClass {

    public static void main(String[] args) {

        ZooKeeper keeper = new ZooKeeper();

        List<Animal> animals = new LinkedList<Animal>();

        animals.add(new Badger());
        animals.add(new Condor());

        keeper.processNewAnimals(animals);

    }
}

任何地方都没有警告,但 ap.process(critter) 无法编译。 我知道这是因为AnimalProcessor&lt;Bird&gt; 不是AnimalProcessor&lt;Animal&gt; 类型的,但我看不出如何解决这个问题。对&lt;T extends Animal&gt;getAnimalProcessor() 的调用将返回一个合适的AnimalProcessor&lt;T extends Animal&gt;,但我无法在代码中表达这一点。

也许我一开始就不应该把 AnimalProcessor 拉出来?

目标当然是能够添加Reptile,而无需更改核心。

【问题讨论】:

  • 为什么 Animal 是接口而不是抽象类?接口应该是某种共享行为。
  • 我明白你的意思,我已经在我的代码中更改了它 - 但编译错误仍然存​​在。

标签: java oop design-patterns generics


【解决方案1】:
public interface Animal<THIS extends Animal<THIS>> {
    AnimalProcessor<THIS> getAnimalProcessor();
}
public abstract class Mammal implements Animal<Mammal> {

有点像Enum&lt;E extends Enum&lt;E&gt;&gt;

删除该方法可能是一个更好的主意。

【讨论】:

  • 我不相信我以前见过这种方法?它有名字吗?
  • 对不起,删除哪个方法?获取动物处理器()?在这种情况下,您将如何使其余代码发挥作用?
  • 我应该指出,我特意添加了 getAnimalProcessor 方法,以便将两个并行继承层次结构(Animal vs AnimalProcessor)联系在一起。
  • 在我的理想世界中,我不会让动物知道如何处理它……这样我就可以在动物园、农场或填色书中重复使用我的动物,而不会造成污染带来的代码。
  • @pjm56 您可以将getAnimalProcessor 替换为process。如果你不想让Animals 知道AnimalProcessors,那么在你构造Animal 的时候,用相关的AnimalProcessor 将它打包到另一个对象中。
【解决方案2】:

AnimalProcessor.java:

public interface AnimalProcessor<T extends Animal> {
    public void process(Animal critter);
}

MammalProcessor.java

public class MammalProcessor implements AnimalProcessor<Mammal> {
    @Override
    public void process(Animal a) {
        System.out.println("Tooth count is " + ((Mammal)a).getToothCount());
    }
}

【讨论】:

  • 感谢 Iga - 我可以看到这会起作用,但希望我可以巧妙地使用泛型来避免沮丧。我认为您无法避免这一点的根本原因是 getAnimalProcessor 方法可以让您取出一只动物的处理器,并可能将其与任何其他动物一起使用(这可能是错误的子类型)。在某些类型将匹配的地方,如果不果断地使用强制转换,也许不可能“平方这个圆”。对这样的演员有什么风格建议吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-09-24
  • 1970-01-01
相关资源
最近更新 更多