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>>
You are actually close to the correct answer.
So i think Point<? extends Float> p = new Point() is the correct code
Yes, this code is exactly correct,and you think of them as having an inheritance relationship
It is easier to illustrate the problem if you compare Float and Number.
Float is extends Number, so Float[] is extends Number[] we call that 'Covariance'.
but Point<Float> is not extends Point<Number>, we call that generics is 'Invariance'
But the magic is Point<Float> 'extends' Point<? extends Number>(At least we can see them as having an inheritance relationship)
So, we can use Point<? extends Number> p = new Point<Float>() and Point<? extends Float> p = new Point<Float>().
In your code, you want to assign List<Point<Float>> to List<Point<? extends Float>>(cause T is Float, so List<Point<? extends T>> is List<Point<? extends Float>>)
but as generics is 'Invariance', although Point<Float> 'extends' Point<? extends Float>, but List<Point<Float>> not extends List<Point<? extends Float>>.
what you should do is change the List<Point<? extends T>> to List<? extends Point<? extends T>>
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.
Related
I've read awesome "Effective Java" by Joshua Bloch. But one example in the books is left unclear to me. It's taken from chapter about generics, exact item is "Item 28: Use bounded wildcards to increase API flexibility".
In this item it's shown how to write the most universal and bulletproof (at the type system point of view) version of the algorithm of selection maximum element from collection using bounded type parameters and bounded wildcard types.
The final signature of the static method written looks like this:
public static <T extends Comparable<? super T>> T max(List<? extends T> list)
And it's mostly the same as the one of Collections#max function from standard library.
public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll)
I understand why we need bounded wildcard in T extends Comparable<? super T> type constraint, but is it really necessary in type of the argument? It seems to me that it will be the same if we leave just List<T> or Collection<T>, isn't it? I mean something like this:
public static <T extends Comparable<? super T>> T wrongMin(Collection<T> xs)
I've written the following silly example of using both signatures and don't see any diferrence:
public class Algorithms {
public static class ColoredPoint extends Point {
public final Color color;
public ColoredPoint(int x, int y, Color color) {
super(x, y);
this.color = color;
}
#Override
public String toString() {
return String.format("ColoredPoint(x=%d, y=%d, color=%s)", x, y, color);
}
}
public static class Point implements Comparable<Point> {
public final int x, y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
#Override
public String toString() {
return String.format("Point(x=%d, y=%d)", x, y);
}
#Override
public int compareTo(Point p) {
return x != p.x ? x - p.x : y - p.y;
}
}
public static <T extends Comparable<? super T>> T min(Collection<? extends T> xs) {
Iterator<? extends T> iter = xs.iterator();
if (!iter.hasNext()) {
throw new IllegalArgumentException("Collection is empty");
}
T minElem = iter.next();
while (iter.hasNext()) {
T elem = iter.next();
if (elem.compareTo(minElem) < 0) {
minElem = elem;
}
}
return minElem;
}
public static <T extends Comparable<? super T>> T wrongMin(Collection<T> xs) {
return min(xs);
}
public static void main(String[] args) {
List<ColoredPoint> points = Arrays.asList(
new ColoredPoint(1, 2, Color.BLACK),
new ColoredPoint(0, 2, Color.BLUE),
new ColoredPoint(0, -1, Color.RED)
);
Point p1 = wrongMin(points);
Point p2 = min(points);
System.out.println("Minimum element is " + p1);
}
So can you suggest an example where such simplified signature will be inacceptable?
P.S. And why the heck there is T extends Object in official implementation?
Answer
Well, thanks to #Bohemian I've managed to figure out what's the difference between them.
Consider the following two auxiliary methods
private static void expectsPointOrColoredPoint(Point p) {
System.out.println("Overloaded for Point");
}
private static void expectsPointOrColoredPoint(ColoredPoint p) {
System.out.println("Overloaded for ColoredPoint");
}
Sure, it's not very smart to overload method both for superclass and its subclass, but it let us see what type of return value was actually inferred (points is List<ColoredPoint> as before).
expectsPointOrColoredPoint(min(points)); // print "Overloaded for ColoredPoint"
expectsPointOrColoredPoint(wrongMin(points)); // print "Overloaded for ColoredPoint"
For both methods inferred type was ColoredPoint.
Sometimes you want be explicit about type passed to overloaded function. You may do it a couple of ways:
You can cast:
expectsPointOrColoredPoint((Point) min(points)); // print "Overloaded for Point"
expectsPointOrColoredPoint((Point) wrongMin(points)); // print "Overloaded for Point"
Still no difference...
Or you can tell compiler what type should be inferred using syntax class.<type>method:
expectsPointOrColoredPoint(Algorithms.<Point>min(points)); // print "Overloaded for Point"
expectsPointOrColoredPoint(Algorithms.<Point>wrongMin(points)); // will not compile
Aha! Here is the answer. List<ColoredPoint> can't be passed to function expecting Collection<Point> because generics are not covariant (unlike arrays), but can be passed to function expecting Collection<? extends Point>.
I'm not sure where or who may prefer to use explicit type parameter in such case, but at least it shows where the wrongMin may be inappropriate.
And thanks to #erickson and #tom-hawtin-tackline for answers about purpose of T extends Object constraint.
The difference is in the type returned, especially influenced by inference, whereby the type may be a type hierarchically between the Comparable type and the List type. Let me give an example:
class Top {
}
class Middle extends Top implements Comparable<Top> {
#Override
public int compareTo(Top o) {
//
}
}
class Bottom extends Middle {
}
Using the signature you've provided:
public static <T extends Comparable<? super T>> T max(List<? extends T> list)
we can code this without errors, warnings or (importantly) casts:
List<Bottom> list;
Middle max = max(list); // T inferred to be Middle
And if you need a Middle result, without inference, you can explicitly type the call to Middle:
Comparable<Top> max = MyClass.<Middle>max(list); // No cast
or to pass to a method that accepts Middle (where inference won't work)
someGenericMethodThatExpectsGenericBoundedToMiddle(MyClass.<Middle>max(list));
I don't know if this helps, but to illustrate the types the compiler as allowed/inferred, the signature would look like this (not that this compiles, of course):
public static <Middle extends Comparable<Top>> Middle max(List<Bottom> list)
The difference between
T max(Collection<? extends T> coll)
and
T wrongMax(Collection<T> xs)
is that the return type of the second version is exactly the same as the collection's element type T, while in the first version T can be a super type of the element type.
The second question: the reason for T extends Object makes sure that T is a class and not an interface.
Update: A slightly more "natural" demonstration of the difference: Suppose you define these two methods:
static void happy(ColoredPoint p, Point q) {}
static void happy(Point p, ColoredPoint q) {}
And call the first one them like this:
happy(coloredPoint, min(points));
happy(coloredPoint, wrongMin(points));
The type inference engine could be able to deduce that in the first call the return type of min should be Point and the code would compile. The second call would fail to compile since the call to happy is ambiguous.
Unfortunately the type inference engine isn't powerful enough at least in Java 7, so in reality both calls fail to compile. The difference is that the first call can be fixed by specifying the type parameter as in Algorithms.<Point>min, while fixing the second call would require an explicit cast.
Not an easy one, but i'll try to be as specific as possible:
in T max(Collection<? extends T> coll)
you could pass an argument like this List<Animal> or List<Cat> or List<Dog>,
and in T wrongMax(Collection<T> xs)
where T is Animal you can't pass as an Argument this
List<Dog>, List<Cat> of course in Runtime you could add Cat or Dog objects in List<Animal> but in compilation time you wouldn't be able to pass a subclass of Animal in the Type of the List being passed as an argument in the wrongMax method, in the other hand, in the max method you could. Sorry for my english, i still learning it :), Regards.
I have a couple of questions about generic wildcards in Java:
What is the difference between List<? extends T> and List<? super T>?
What is a bounded wildcard and what is an unbounded wildcard?
In your first question, <? extends T> and <? super T> are examples of bounded wildcards. An unbounded wildcard looks like <?>, and basically means <? extends Object>. It loosely means the generic can be any type. A bounded wildcard (<? extends T> or <? super T>) places a restriction on the type by saying that it either has to extend a specific type (<? extends T> is known as an upper bound), or has to be an ancestor of a specific type (<? super T> is known as a lower bound).
The Java Tutorials have some pretty good explanations of generics in the articles Wildcards and More Fun with Wildcards.
If you have a class hierarchy A, B is a subclass of A, and C and D are both subclasses of B like below
class A {}
class B extends A {}
class C extends B {}
class D extends B {}
Then
List<? extends A> la;
la = new ArrayList<B>();
la = new ArrayList<C>();
la = new ArrayList<D>();
List<? super B> lb;
lb = new ArrayList<A>(); //fine
lb = new ArrayList<C>(); //will not compile
public void someMethod(List<? extends B> lb) {
B b = lb.get(0); // is fine
lb.add(new C()); //will not compile as we do not know the type of the list, only that it is bounded above by B
}
public void otherMethod(List<? super B> lb) {
B b = lb.get(0); // will not compile as we do not know whether the list is of type B, it may be a List<A> and only contain instances of A
lb.add(new B()); // is fine, as we know that it will be a super type of A
}
A bounded wildcard is like ? extends B where B is some type. That is, the type is unknown but a "bound" can be placed on it. In this case, it is bounded by some class, which is a subclass of B.
Josh Bloch also has a good explanation of when to use super and extends in this google io video talk where he mentions the Producer extends Consumer super mnemonic.
From the presentation slides:
Suppose you want to add bulk methods to Stack<E>
void pushAll(Collection<? extends E> src);
– src is an E producer
void popAll(Collection<? super E> dst);
– dst is an E consumer
There may be times when you'll want to restrict the kinds of types that are allowed to be passed to a type parameter. For example, a method that operates on numbers might only want to accept instances of Number or its subclasses. This is what bounded type parameters are for.
Collection<? extends MyObject>
means that it can accept all object who have IS- A relationship with MyObject (i.e. any object which is a type of myObject or we can say any object of any subclass of MyObject) or a object of MyObject class.
For example:
class MyObject {}
class YourObject extends MyObject{}
class OurObject extends MyObject{}
Then,
Collection<? extends MyObject> myObject;
will accept only MyObject or children of MyObject(i.e. any object of type OurObject or YourObject or MyObject, but not any object of superclass of MyObject).
In general,
If a structure contains elements with a type of the form ? extends E, we can get elements out of the structure, but we cannot put
elements into the structure
List<Integer> ints = new ArrayList<Integer>();
ints.add(1);
ints.add(2);
List<? extends Number> nums = ints;
nums.add(3.14); // compile-time error
assert ints.toString().equals("[1, 2, 3.14]");
To put elements into the structure we need another kind of wildcard called Wildcards with super,
List<Object> objs = Arrays.<Object>asList(2, 3.14, "four");
List<Integer> ints = Arrays.asList(5, 6);
Collections.copy(objs, ints);
assert objs.toString().equals("[5, 6, four]");
public static <T> void copy(List<? super T> dst, List<? extends T> src) {
for (int i = 0; i < src.size(); i++) {
dst.set(i, src.get(i));
}
}
Generic wildcards are created to make methods that operate on Collection more reusable.
For example, if a method has a parameter List<A>, we can only give List<A> to this method. It is a waste for this method's funtion under some circumstances:
If this method only reads objects from List<A>, then we should be allowed to give List<A-sub> to this method. (Because A-sub IS a A)
If this method only inserts objects to List<A>, then we should be allowed to give List<A-super> to this method. (Because A IS a A-super)
learn by example:
consider the sort() method in Collections class which use both extends and super:
public static <T extends Comparable<? super T>> void sort(List<T> list){...}
so
why <T extends Comparable<...>>: becuase we need list items (T) to be a subclass of the Comparable interface.
why Comparable<? super T>: becuase we allow the Comparable type
to be a Comparable of any super type of T.
Consider
interface Comparable<T>{
public int compareTo(T o);
}
public static <T extends Comparable<? super T>> void sort(List<T> list){...}
public static <T extends Comparable<T>> void sort2(List<T> list){...}
class A implements Comparable<A>{
#Override
public int compareTo(A o) {
...
}
}
class B extends A {
}
List<A> listA = new ArrayList<>();
List<B> listB = new ArrayList<>();
sort(listA); //ok
sort(listB); //ok
sort2(listA); //ok
sort2(listB); //Error
The SCCE below shows 2 classes (B and C) implementing the interface Marker. For each class that implements Marker there is a corresponding class implementing the generic Handler interface (B_Handler, C_Handler). A map is used to associate the Class type of Pair.second to it's associated Handler. The code executes as anticipated; however, I get a compile-time warning:
warning: [unchecked] unchecked cast
Handler h1 = (Handler) (dispatch.get(p1.second.getClass()));
required: Handler
found: Handler
where CAP#1 is a fresh type-variable:
CAP#1 extends Marker from capture of ? extends Marker
What's the cleanest way to resolve this besides #SuppressWarnings(value = "unchecked")?
package genericpair;
import java.util.HashMap;
import java.util.Map;
import javax.swing.SwingUtilities;
public class GenericPair
{
public class A
{
}
public interface Marker
{
}
public class B implements Marker
{
}
public class C implements Marker
{
}
public Pair<A, Marker> getTarget()
{
A a = new A();
C c = new C();
return new Pair<>(a, c);
}
public interface Handler<T extends Marker>
{
void handle(Pair<A, T> target);
}
public class B_Handler implements Handler<B>
{
#Override
public void handle(Pair<A, B> target)
{
System.out.println("B");
}
}
public class C_Handler implements Handler<C>
{
#Override
public void handle(Pair<A, C> target)
{
System.out.println("C");
}
}
public class Pair<F, S>
{
public final F first;
public final S second;
public Pair(F first, S second)
{
this.first = first;
this.second = second;
}
}
private void executeSCCE()
{
// register a handler for each Marker type
Map<Class, Handler<? extends Marker>> dispatch = new HashMap<>();
dispatch.put(B.class, new B_Handler());
dispatch.put(C.class, new C_Handler());
// get a target (e.g., Pair<A,C>)
Pair<A, Marker> p1 = getTarget();
// select handler based on the class type of the second parameter
Handler<Marker> h1 = (Handler<Marker>) (dispatch.get(p1.second.getClass()));
h1.handle(p1);
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(() -> new GenericPair().executeSCCE());
}
}
Consider the following example:
List<? extends List> test1 = new ArrayList<>();
List<List> test2 = (List<List>) test1;
Here we get the warning:
warning: [unchecked] unchecked cast
List<List> test2 = (List<List>) test1;
^
required: List<List>
found: List<CAP#1>
where CAP#1 is a fresh type-variable:
CAP#1 extends List from capture of ? extends List
This happens because there is no way to ensure that the generic constraint of List<List> will match List<? extends List>. Imagine that we rewrite this example to the following:
List<? extends List> test1 = new ArrayList<ArrayList>();
List<List> test2 = (List<List>) test1;
test1.add(new LinkedList<>());//ERROR no suitable method found for add(LinkedList<Object>)
test2.add(new LinkedList<>());//Will work fine!!
Here it is more obvious that the initial contract is broken. The list defined to contain ArrayList now contains a LinkedList. This is unsafe, and is why you are getting this warning. So there is no way to cast from Handler<? extends Marker> to Handler<Marker> safely.
There are several issues.
The first is that your Map is not able to express the type relationship between each key and its value. So if you pass a Class<T> to dispatch.get(), you only get a Handler<? extends Marker> back, not Handler<T>. In fact, there is no type you can give dispatch to make that work. Instead, you have to make a wrapper class to enforce this relationship via its API:
public class ClassToHandlerMap
{
private final Map<Class<?>, Handler<?>> map = new HashMap<>();
public <T extends Marker> void put(Class<T> clazz, Handler<T> handler) {
map.put(clazz, handler);
}
#SuppressWarnings("unchecked")
public <T extends Marker> Handler<T> get(Class<T> clazz) {
return (Handler<T>)map.get(clazz);
}
}
Note that you do still have to suppress unchecked warnings inside this class, but at least here you know it's provably correct, based on how things are allowed to be put into the map. The unchecked cast is just an implementation detail that the user of this class doesn't need to know about.
The second issue is that getTarget() should probably return Pair<A, ? extends Marker> instead of Pair<A, Marker>. You don't ever have a Handlers of Marker; rather, you have Handlers of particular types of Marker. So it makes sense that you only use Pairs of particular types of Marker too.
public Pair<A, ? extends Marker> getTarget()
{
A a = new A();
C c = new C();
return new Pair<>(a, c);
}
The last part of your function basically is using p1 to operate on itself, so we need to use a capture helper to "capture" the ? in the type of p1 into a useful type variable for what we need to do.
However, this is more complicated in this case, because you are using .getClass(). foo.getClass() has the type Class<? extends |X|> where |X| is the erasure of the compile-time type of foo. So no matter if p1 had the type Pair<A, ?> or Pair<A, T>, p1.second.getClass() would still return the type Class<? extends Marker>. So capturing on the ? in Pair<A, ?> is not enough; instead, we should capture on the ? in the return of .getClass():
#SuppressWarnings("unchecked")
private static <T extends Marker> void captureHelper(Class<T> clazz,
Pair<A, ? extends Marker> p, ClassToHandlerMap dispatch) {
Pair<A, T> p1 = (Pair<A, T>)p;
Handler<T> h1 = dispatch.get(clazz);
h1.handle(p1);
}
Unfortunately, we will have to do an unchecked cast here also. Due to the peculiar return type of .getClass() we are unable to connect the types of the return of .getClass() and the expression it is called on. And we can't use runtime casting like .cast() to cast between parameterized types (we could use .cast() to get rid of unchecked casts if we were taking an instance of the given class as an argument, but not here). There may be some edge cases in which this is incorrect, but as long as you always use Pair with the second type argument being a final implementing class, it should be correct.
And finally the primary method looks like this:
private void executeSCCE()
{
// register a handler for each Marker type
ClassToHandlerMap dispatch = new ClassToHandlerMap();
dispatch.put(B.class, new B_Handler());
dispatch.put(C.class, new C_Handler());
// get a target (e.g., Pair<A,C>)
Pair<A, ? extends Marker> p1 = getTarget();
// select handler based on the class type of the second parameter
captureHelper(p1.second.getClass(), p1, dispatch);
}
Here is my problem:
my function in class A:
public void setData(Map<String,? extends ArrayList<? extends SomeInterface>>){...}
my call:
Map<String, ArrayList<ImplementsSomeInterface>> a=...;
instanceOfA.setData(a); //does not compile
instanceOfA.setData((Map<String,? extends ArrayList<? extends SomeInterface>>) a); // works thanks to the Casting.
I don't think this is clean. Is there a way to avoid the casting without droping the wildcard use in the function?
First your setData method should read:
public void setData(Map<String,? extends List<? extends SomeInterface>>)
Your map declaration should read:
Map<String, List<ImplementsSomeInterface>> a = ...;
Which is pretty much what you've got following your edits to the original question. The change I've made from ArrayList to List doesn't effect the behaviour of the code.
Following comments:
public static void main()
{
Map<String, List<Double>> map = new HashMap<String, List<Double>>();
map.put("prices", new ArrayList<Double>(Arrays.asList(1.1, 2.2, 3.3)));
setData(map);
}
public static void setData(Map<String,? extends List<? extends Serializable>> map)
{
}
The problem is that setData takes as an argument a
Map<String,? extends ArrayList<? extends SomeClass>>Map>
whereas in your first call(the one that doesn't compile) you are trying to pass it a Map<String,? extends SomeClass>
Java cannot automatically cast a subclass of
SomeClass
to a subclass of
ArrayList<? extends SomeClass>
because it is not neccesarily an instance of ArrayList.
package pkg_2;
import java.util.*;
class shape{}
class Rect extends shape{}
class circle extends shape{}
class ShadeRect extends Rect{}
public class OnTheRun {
public static void main(String[] args) throws Throwable {
ShadeRect sr = new ShadeRect();
List<? extends shape> list = new LinkedList<ShadeRect>();
list.add(0,sr);
}
}
You cannot add anything to a List<? extends X>.
The add cannot be allowed because you do not know the component type. Consider the following case:
List<? extends Number> a = new LinkedList<Integer>();
a.add(1); // in this case it would be okay
a = new LinkedList<Double>();
a.add(1); // in this case it would not be okay
For List<? extends X> you can only get out objects, but not add them.
Conversely, for a List<? super X> you can only add objects, but not get them out (you can get them, but only as Object, not as X).
This restriction fixes the following problems with arrays (where you are allowed these "unsafe" assigns):
Number[] a = new Integer[1];
a[0] = 1; // okay
a = new Double[1];
a[0] = 1; // runtime error
As for your program, you probably just want to say List<shape>. You can put all subclasses of shape into that list.
ShadeRect sr = new ShadeRect();
List<shape> list = new LinkedList<shape>();
list.add(0,sr);