Consider the following code (the two questions are inside the code):
import java.util.*;
public class Tree<T> {
private T info;
private List<Tree<? extends T>> children = new ArrayList<Tree<? extends T>>();
public Tree<? extends T> getChildren(int n) {
return children.get(n);
}
public void addChildren(Tree<? extends T> children) {
this.children.add(children);
}
public static void main(String[] args) {
Tree<?> b2; // so b2 is a reference of a Tree of unknown type
b2 = new Tree<Number>(); /* to allow b2 to call addChildren() with Tree<? extends Number> aguments */
b2.addChildren(new Tree<Number>()); // 1) why it doesn't work ?
b2.addChildren(new Tree<Integer>()); // neither does this one!
b2.addChildren(new Tree<>()); // 2) but with diamond <> it works ?
}
}
- Why does
b2.addChildren(new Tree<Number>())
not work? - But it works with diamond <>
b2.addChildren(new Tree<>())
. Which type list the compiler uses inside the diamond <>?
The problem is that you have declared
b2
to have a type ofTree<?>
.The problem is clearer if you rewrite your main method as two methods:
Even though you created a
new Tree<Number>()
, you are immediately discarding that information. Your code is only remembering thatb2
contains some unknown type of Tree, sinceTree<?>
means "some type of Tree but I don't know what type."Since we don't know what the Tree's type is, how do we know if it's safe to call
addChildren(new Tree<Number>())
, ornew Tree<Integer>()
ornew Tree<String>()
ornew Tree<JTable>()
? The compiler has no idea. You may remember what you put in there, but the type ofb2
doesn't carry that information, so the compiler doesn't have any way to know.