简体   繁体   中英

Type mismatch: cannot convert from Map<String,List<Animal>> to Map<String,List<Dog>>

I am having some trouble solving a problem with generics. I have a list of "Cat" objects and a list of "Dog" objects that I need to pass into the same method. The return type for that method is a Map of "String" and a "List of Animals" I am trying to figure out a way to convert the Maps with the list of animals into a Map with a list of Cats or Dogs.

This works fine if I have a separate method for Cats and Dogs but I'm looking for a more flexible solution.

Lines getting the error in title:

catMap = PetStore.groupAnimalsByOwner(cats); 
dogMap = PetStore.groupAnimalsByOwner(dogs);

Note: this is a simplified example, I have to be able to use the Lists in the Maps as "Cat" or "Dog" objects.

    public class Start {

    public static void main(String[] args) {

        Cat cat1 = new Cat("Jerry", "cat1");
        Cat cat2 = new Cat("Jerry", "cat2");
        Cat cat3 = new Cat("Fred", "cat3");

        List<Cat> cats = new LinkedList<Cat>();
        cats.add(cat1);
        cats.add(cat2);
        cats.add(cat3);

        Dog dog1 = new Dog("Frank", "dog1");
        Dog dog2 = new Dog("Jerry", "dog2");
        Dog dog3 = new Dog("Bob", "dog3");

        List<Dog> dogs = new LinkedList<Dog>();
        dogs.add(dog1);
        dogs.add(dog2);
        dogs.add(dog3);

        Map<String, List<Dog>> dogMap = new HashMap<String, List<Dog>>();
        Map<String, List<Cat>> catMap = new HashMap<String, List<Cat>>();

        // catMap should have 2 key/value pairs - key "Jerry" with a list containing cat1 and cat2
        // and a pair - key "Fred" with a list containing only cat3
        catMap = PetStore.groupAnimalsByOwner(cats); 

        // dogMap should have 3 key/value pairs - key "Frank" with a list containing dog1
        // key "Jerry" with a list containing dog2
        // Key "Bob" with a list containing dog3
        dogMap = PetStore.groupAnimalsByOwner(dogs);

    }

}


public class PetStore {

    //Grouping by owner
    public static Map<String, List<Animal>> groupAnimalsByOwner(List<? extends Animal> animals) {
        Map<String, List<Animal>> groupedMap = new HashMap<String, List<Animal>>();
        List<Animal> tempList = null;

        for (Animal summary : animals) {
            String consolidatedInvoiceId = summary.getOwner();
            tempList = groupedMap.get(consolidatedInvoiceId);
            if (tempList == null) {
                tempList = new LinkedList<Animal>();
            }
            tempList.add(summary);
            groupedMap.put(consolidatedInvoiceId, tempList);
        }

        return groupedMap;
    }
}


public interface Animal {

    public String getOwner();
}


  public class Cat implements Animal {

    private String owner;
    private String name;

    public Cat(String owner, String name) {
        this.owner = owner;
        this.name = name;
    }


    @Override
    public String getOwner() {
        return owner;
    }

    public String getName() {
        return name;
    }

    public void doCatStuff() {
        System.out.println("Do cat stuff");
    }

}

The Dog class is the same as Cat but with a doCatStuff method.

Thank you in advance.

Just as a List<Dog> isn't a List<Animal> , a Map<String, List<Cat>> is not a Map<String, List<Animal>> .

Make your groupAnimalsByOwner method generic, with Animal as an upper bound, so that T is inferred to be Cat (or Dog ). You'll need to replace Animal with T in the body of the method.

public static <T extends Animal> Map<String, List<T>> 
         groupAnimalsByOwner(List<? extends T> animals)
{
    Map<String, List<T>> groupedMap = new HashMap<String, List<T>>();
    List<T> tempList = null;

    for (T summary : animals) {
        String consolidatedInvoiceId = summary.getOwner();
        tempList = groupedMap.get(consolidatedInvoiceId);
        if (tempList == null) {
            tempList = new LinkedList<T>();
        }
        tempList.add(summary);
        groupedMap.put(consolidatedInvoiceId, tempList);
    }

    return groupedMap;
}

You declared the method as returning Map<String, List<Animal>> . This type is not compatible with Map<String, List<Dog>> because a List<Animal> is not compatible with List<Dog> . Those are not compatible because the first declaration, List<Animal> , does not allow any subtypes of Animal . Secondly, while all Dog s are Animal s, not all Animal s are Dog s.

For this scenario, what you need is a placeholder.

public static <T extends Animal> Map<String, List<T>>  groupAnimalsByOwner(List<T> animals) {

change List<Cat> and List<Dog> to List<Animal>

maybe this will help: https://docs.oracle.com/javase/tutorial/java/generics/inheritance.html

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM