展平通用Java树

时间:2011-10-07 16:07:01

标签: java generics tree javac

我有一个可以拥有父母和孩子的模型的界面

public interface HierarchyAware<T extends HierarchyAware<T>> {

  List<T> getChildren();

  T getParent();

  void addChild(T child);

}

我有一个实用工具方法,它采用一个平面列表并构建一个树:

<T extends HierarchyAware<? super T>> List<T> buildTree(List<T> flatElements);

它运行正常,因此无需发布方法体。

我还有一个将树展平为普通列表的方法:

  public static List<? extends HierarchyAware<?>> flattenTree(List<? extends HierarchyAware<?>> treeElements) {
    List<HierarchyAware<?>> flatList = new ArrayList<HierarchyAware<?>>();
    for (HierarchyAware<?> t : treeElements) {
      flatList.add(t);
      if (t.getChildren() != null) {
        flatList.addAll(flattenTree(t.getChildren()));
      }
    }
    return flatList;
  }

但我真的不喜欢它的签名,并希望让它更具体。所以我把它编码为:

  @SuppressWarnings("unchecked")
  public static <T extends HierarchyAware<? super T>> List<T> flattenTree(List<T> treeElements) {
    List<T> flatList = new ArrayList<T>();
    for (T t : treeElements) {
      flatList.add(t);
      if (t.getChildren() != null) {
        flatList.addAll((List<? extends T>) flattenTree(t.getChildren()));
      }
    }
    return flatList;
  }

签名非常适合我,但我不喜欢压制警告的必要性。最大的问题是Eclipse编译器发现这个代码是合法的,但是javac给了我:

[javac] C:\somepath\TreeUtil.java:112: <T>flattenTree(java.util.List<T>) in somepackage.TreeUtil cannot be applied to (java.util.List<capture#687 of ? super T>)
[javac]         flatList.addAll((List<? extends T>) flattenTree(t.getChildren()));
[javac]                                             ^

为什么两个编译器的行为方式不同?我应该如何重写此方法,以便它是错误的,理想情况下是无警告的?

1 个答案:

答案 0 :(得分:2)

在此之前,似乎存在一个概念问题:

作为层次结构知道某些基类会阻止在编译时让派生类的子句(getChildren)。所以安全地获取派生类的List总是不安全的。

如果你不是说A级只有A级孩子,那么就是这样。那是可行的。

    public static <T extends HierarchyAware<T>> List<T> flattenTreeX(List<T> treeElements) {
    List<T> flatList = new ArrayList<T>();
    for (T t : treeElements) {
        flatList.add(t);
        if (t.getChildren() != null) {
            flatList.addAll((List<? extends T>) flattenTreeX(t.getChildren()));
        }
    }
    return flatList;