1

I have 2 classes that are linked using Generic Wildcards

    import java.util.*;
    public class Main
    {
        public static void main(String[] args){
            AnotherClass another = new AnotherClass();
            List<Integer> a1 = new ArrayList<Integer>();
            a1.add(1);
            another.runtest(a1);
        }
        
    }
    import java.util.*;
    public class AnotherClass {
        public void runtest(List<? extends Number> a){
            a.add(2);
        }
    }

But while executing the above code I am getting exceptions as below:

    AnotherClass.java:4: error: no suitable method found for add(int)
            a.add(2);
             ^
        method Collection.add(CAP#1) is not applicable
          (argument mismatch; int cannot be converted to CAP#1)
        method List.add(CAP#1) is not applicable
          (argument mismatch; int cannot be converted to CAP#1)
      where CAP#1 is a fresh type-variable:
        CAP#1 extends Number from capture of ? extends Number
    Note: Some messages have been simplified; recompile with -Xdiags:verbose to get full output
    1 error

Can someone help me to write the Code in better way or how can we use wildcards during method call. I am not able to understand why it is now allowing extends in method definition.

Andy Turner
  • 137,514
  • 11
  • 162
  • 243
  • please remove your first line from code fences. – nima Aug 20 '21 at 08:34
  • @BenjaminM Thank You very much for the reference. It solved all my doubts. :) – Mohit Yadav Aug 20 '21 at 08:37
  • `List extends Number>` is a list which contains *some* ok instances of *some* subclass of `Number` - significantly, you don't know which. It could be a `List`, a `List`, even `List`. As such, the compiler doesn't know if it is safe to add an `Integer` to it. – Andy Turner Aug 20 '21 at 08:41

2 Answers2

0

List<? extends Number> is a list which contains instances of some subclass of Number - significantly, you don't know which. It could be a List<Integer>, a List<Double>, even List<MyCustomImplementationOfNumber>.

For example, a List<Double> is expected only to contain instances of Double (or null). If you were allowed to add an Integer to that list on this method, you would be violating this expectation on the subsequent contents of the Double.

The compiler doesn't know if it is safe to add an Integer to it.

The fix is to pass a list to which it is known to be safe to add an Integer. Any of the following would work (amongst others):

public void runtest(List<Integer> a){
public void runtest(List<Number> a){
public void runtest(List<? super Integer> a){
public void runtest(List<? super Number> a){

A super bound (a lower bound) says "I don't know the exact bound on the type; but I know it is some superclass". Since all instances of a subclass are instances of a superclass, it is safe to add instances of the subclass to the list, hence it is allowed.

Andy Turner
  • 137,514
  • 11
  • 162
  • 243
0

Ideally in such code as this you would want to read and act upon the data in the list, perhaps removing items, not modify the list by adding items as you will get into issues like the above, because the code cannot guarantee that the autoboxing Integer type can be added to the List, as it could also be an ArrayList<Double>.

If you wish to modify the list you will need to target specific type of numbers, like Integer or Double or Float etc....

In short, my recommendation is, use such a construct for reading/filtering/splitting/deleting, but not for adding items.

Tschallacka
  • 27,901
  • 14
  • 88
  • 133