The constructor of Plane
in your call takes a List<Points<? extends Float>>
, but you are passing it a List<Points<Float>>
.
The relationship between Points<? extends Float>
and Points<Float>
is exactly like that of Number
and Integer
- one is the subtype of another. Compare:
// in both cases, you are assigning an instance of a subtype to a variable of a supertype
Points<? extends Float> p = new Points<Float>();
Number n = Integer.valueOf(1);
So trying to pass (or implicitly convert) a List<Points<Float>>
into a List<Points<? extends Float>>
is just like trying to do that with a List<Integer>
and List<Number>
. As you probably know already, it doesn't work at all because allowing you to do this would make it unsafe to add things into the list:
List<Integer> integers = new ArrayList<>();
List<Number> numbers = integers; // suppose this is allowed...
numbers.add(0.1f); // I can now add a float into the integer list!
In practice though, I think the same thing cannot happen with List<Points<? extends Float>>
and List<Points<Float>>
, because it is not possible to create another concrete subtype of Points<? extends Float>
that is also not a subtype of Points<Float>
. This is mainly because Float
is final
. However, the Java compiler isn't designed to see this.
List<Points<Float>> floatPoints = new ArrayList<>();
List<Points<? extends Float>> extendsFloatPoints = floatPoints; // suppose this is allowed
extendsFloatPoints.add(/* whatever you can add here can be added to floatPoints */);
One way to fix the error, is as you have found, to add ? extends
. In your case, this means:
private List<? extends Points<? extends T>> points;
public Plane() { }
public Plane(List<? extends Points<? extends T>> points) {
this.points = points;
}
Note that this is in addition to the ? extends
in the type parameter of Points
. This is analogous to turning List<Number> numbers = new ArrayList<Integer>();
into List<? extends Number> numbers = new ArrayList<Integer>();
This essentially prevents you from adding anything into the list except nulls.
Another way to solve the problem is to create a List<Points<? extends Float>>
from the very beginning and pass that into the constructor. It is totally possible to do:
List<Points<? extends Float>> lp = new ArrayList<>();
lp.add(new Points<Float>(1f, 2f));
// add more points...
Plane<Float> plane = new Plane<>(lp);
A third way is to just get rid of all the wildcard all together, and just use List<Points<T>>
everywhere. I don't see much value in using them, since most of the Number
subclasses are final
anyway.