我有一个可以拥有父母和孩子的模型的界面
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] ^
为什么两个编译器的行为方式不同?我应该如何重写此方法,以便它是错误的,理想情况下是无警告的?
答案 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;