What proper use of generics resolves this compilation error?

Repeating the previous example, imagine a zoo where newly arrived animals should be treated by Zookeeper (think about checking them out at the zoo). Each animal registration process depends on its class taxonomy (mammals, birds, etc.).

The processes differ due to the fundamental differences between the classes of taxonomy - for example, birds have wings, mammals have teeth. You may also have some common bits of the process that are true for all animals, but I omitted them here.

Here is the code:

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

There are no warnings, but ap.process (crter) cannot compile. I know this because AnimalProcessor<Bird> not of type AnimalProcessor<Animal> , but I don’t see how to solve the problem. Calling <T extends Animal> getAnimalProcessor() will return the appropriate AnimalProcessor<T extends Animal> , but I cannot express it in the code.

Perhaps I should not pull out AnimalProcessor in the first place?

The goal is, of course, to add a Reptile without changing the kernel.

+4
source share
2 answers
 public interface Animal<THIS extends Animal<THIS>> { AnimalProcessor<THIS> getAnimalProcessor(); } public abstract class Mammal implements Animal<Mammal> { 

A bit like Enum<E extends Enum<E>> .

It might be better to remove this method.

+5
source

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

All Articles