什么是泛型的正确使用解决了这个编译错误?

时间:2012-06-27 14:35:22

标签: java oop design-patterns generics

重复使用前面的例子,想象一下动物园,动物园管理员必须“处理”新到达的动物(考虑将它们检入动物园)。每只动物的登记过程取决于其类别分类(哺乳动物,鸟类等)。

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

以下是代码:

Animal.java

public interface Animal {

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

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

}

Badger.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<Bird> 类型为AnimalProcessor<Animal>,但我看不出如何解决问题。对<T extends Animal> getAnimalProcessor()的调用将返回合适的AnimalProcessor<T extends Animal>,但我无法在代码中表达此内容。

也许我不应该首先将AnimalProcessor拉出来?

当然,目标是能够在不更改核心的情况下添加Reptile

2 个答案:

答案 0 :(得分:5)

public interface Animal<THIS extends Animal<THIS>> {
    AnimalProcessor<THIS> getAnimalProcessor();
}
public abstract class Mammal implements Animal<Mammal> {

有点像Enum<E extends Enum<E>>

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

答案 1 :(得分: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());
    }
}