2

考虑以下代码(两个问题在代码中):

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 ?
    }
}
  1. 为什么不b2.addChildren(new Tree<Number>())工作?
  2. 但它适用于 diamond <> b2.addChildren(new Tree<>())。编译器在菱形 <> 中使用哪种类型的列表?
4

1 回答 1

5

问题是您已声明b2具有Tree<?>.

如果您将 main 方法重写为两种方法,则问题会更清楚:

public static void main(String[] args) {
    test(new Tree<Number>());
}

private static void test(Tree<?> b2) {
    // "<?>" means we don't know what the generic type of b2 is, so
    // the compiler can't possibly know if it's safe to add any type
    // of children...

    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 ?
}

即使您创建new Tree<Number>(),您也会立即丢弃该信息。您的代码只记住b2包含某种未知类型的树,因为Tree<?>这意味着“某种类型的树,但我不知道是什么类型。”

由于我们不知道 Tree 的类型是什么,我们如何知道调用addChildren(new Tree<Number>()), ornew Tree<Integer>()new Tree<String>()or是否安全new Tree<JTable>()?编译器不知道。你可能记得你放在那里的东西,但是类型b2不携带这些信息,所以编译器没有任何办法知道。

于 2014-12-30T16:13:51.187 回答