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.