I can't assign value to List.
I have two class like this:
public class Point<T extends Number> {
private T x;
private T y;
public Point() { }
public Point(T x, T y) {
this.x = x;
this.y = y;
}
}
public class Plane<T extends Number> {
private List<Point<? extends T>> points;
public Plane() { }
public Plane(List<Point<? extends T>> points) {
this.points = points;
}
}
Then I use List to init a value and use the List to init Plane like this:
List<Point<Float>> lp = new ArrayList<Point<Float>>();
Plane<Float> plane = new Plane<Float>(lp);
I get a error java.util.List<Point<java.lang.Float>> can not cast to java.util.List<Point<? extends java.lang.Float>>
I found this page Difference between <? super T> and <? extends T> in Java, and that said we can use
List<? extends Number> foo3 = new ArrayList<Integer>();.
So i think Point<? extends Float> p = new Point<Float>() is the correct code
Back to my code, I think class Plane's constructor parameters witch type List<Point<? extends T>> points can receive type List<Point<Float>>, but i get that error!
Can you tell me why?
I search in google, why can't use List<someclass> to List<someclass<? extend Float>>
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With