Reputation: 188
I have the following interface with generic and an implentation class:
public interface DataInterface<T> {
T getData();
void printData();
}
public class IntegerData implements DataInterface<Integer> {
private Integer value;
public IntegerData(Integer value) {
this.value = value;
}
@Override
public Integer getData() {
return null;
}
@Override
public void printData() {
System.out.println(this.value);
}
}
And here my code that use the class:
public class Main {
public static void main(String[] args) {
List<IntegerData> dataList = new ArrayList<>();
dataList.add(new IntegerData(1));
doSomething(dataList); <-- Compiler error
//this work
doSomething(Collections.unmodifiableList(dataList));
doSomething(new ArrayList<>(dataList));
}
private static void doSomething(List<DataInterface<?>> dataList) {
for (DataInterface<?> data : dataList)
data.printData();
}
}
If I try to call the doSomething method with the List type, the compiler complains with "The method doSomething(List<DataInterface<?>>) in the type Main is not applicable for the arguments (List)".
But if I wrap my specific list or create a new one, then it works. I wonder why the direct call doesn't work. What is the reason?
Upvotes: 1
Views: 591
Reputation: 9175
A List<IntegerData>
or List<DataInterface<Integer>>
is not compatible with List<DataInterface<?>>
, because I can also add a DataInterface<String>
to the latter. The solution is to use extends:
private static void doSomething(List<? extends DataInterface<?>> dataList)
This will prevent adding anything to the list (except null
), and is therefore safe to use.
By wrapping the list, the generic type is changed due to type inference. If you'd assign it to a variable using var
it would also fail.
Upvotes: 2