Reputation: 1675
I would like to understand why it is not possible to pass wildcards to generics, and what is the best solution for that.
I will use a simple reproducible example, but the code is more complex.
I have a method that takes as a parameter a map of Class<GENERIC_TYPE> as key and List<GENERIC_TYPE> as value.
private <CAR extends Car> void doSomething(final Map<Class<CAR>, List<CAR>> carMap) {
carMap.entrySet().stream().forEach(entry -> {
System.out.println("\n" + entry.getKey().getSimpleName() + "\n" + entry.getValue() + "\n");
});
}
The method that is in charge of passing the map to the method "doSomething" doesn't have generics (and I cannot add bounded generics because is overriding a method of an interface)
so the Map is declared using wildcards:
@Override
public void doSomethingPowerfull() {
Bmw bmwM1 = new Bmw("BMW", "M1");
Bmw bmwM3 = new Bmw("BMW", "M3");
Bmw bmwM5 = new Bmw("BMW", "M5");
List<Bmw> bmw = List.of(bmwM1, bmwM3, bmwM5);
Audi audiS1 = new Audi("Audi", "S1");
Audi audiS3 = new Audi("Audi", "S3");
Audi audiS5 = new Audi("Audi", "S5");
List<Audi> audi = List.of(audiS1, audiS3, audiS5);
Map<Class<? extends Car>, List<? extends Car>> carMap = new HashMap<>();
carMap.put(Audi.class, audi);
carMap.put(Bmw.class, bmw);
doSomething(carMap); // COMPILATION ERROR
// The method doSomething(Map<Class<CAR>,List<CAR>>) in the type TestWildCardGenerics is not applicable for the arguments (Map<Class<? extends TestWildCardGenerics.Car>,List<? extends TestWildCardGenerics.Car>>)
}
They extends the same class, so why I'm not able to pass this map?
Here is the complete test class:
public class TestWildCardGenerics {
public void test() {
Bmw bmwM1 = new Bmw("M1");
Bmw bmwM3 = new Bmw("M3");
Bmw bmwM5 = new Bmw("M5");
List<Bmw> bmw = List.of(bmwM1, bmwM3, bmwM5);
Audi audiS1 = new Audi("S1");
Audi audiS3 = new Audi("S3");
Audi audiS5 = new Audi("S5");
List<Audi> audi = List.of(audiS1, audiS3, audiS5);
Map<Class<? extends Car>, List<? extends Car>> carMap = new HashMap<>();
carMap.put(Audi.class, audi);
carMap.put(Bmw.class, bmw);
doSomething(carMap);
}
private <CAR extends Car> void doSomething(final Map<Class<CAR>, List<CAR>> carMap) {
carMap.entrySet().stream().forEach(entry -> {
System.out.println("\n" + entry.getKey().getSimpleName() + "\n" + entry.getValue() + "\n");
});
}
@Data
@AllArgsConstructor
public abstract class Car {
protected String name;
}
@Data
@ToString(callSuper = true)
public class Audi extends Car {
private String sModel;
public Audi(final String sModel) {
super("Audi");
this.sModel = sModel;
}
}
@Data
@ToString(callSuper = true)
public class Bmw extends Car {
private String mModel;
public Bmw(final String mModel) {
super("BMW");
this.mModel = mModel;
}
}
}
Upvotes: 0
Views: 36
Reputation: 140326
They extends the same class
No, each occurrence of ? extends Car
is considered to be a different type, because they could be different types. The signature of doSomething
requires them to be the same.
Unless there's a good reason for doSomething
to require both Class and List to be bounded by the exact same type, you could simply use a wildcard there:
private void doSomething(final Map<Class<? extends Car>, List<? extends Car>> carMap) {
Upvotes: 1