I have an interface for models that can have parents and children
public interface HierarchyAware<T extends HierarchyAware<T>> {
List<T> getChildren();
T getParent();
void addChild(T child);
}
I have a utility method that takes a flat list and builds a tree:
<T extends HierarchyAware<? super T>> List<T> buildTree(List<T> flatElements);
开发者_如何学编程It works fine, so there's no need to post the method body.
I also have a method that flattens a tree into a plain list:
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;
}
but I really don't like it's signature and want to make it more specific. So I've coded it like this:
@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;
}
Signature is perfect for me, but I don't like the need to suppress warnings. And the biggest problem is that Eclipse compiler finds this code legit, but javac gives me:
[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] ^
Why are two compilers behaving differently and how should I rewrite this method so it would be error and ideally warning-free?
Before all there seems to be a conceptual problem:
Being HierarchyAware of some base class prevents yielding children of derived classes at compile time (getChildren). So safely getting a List of a derived class is always unsafe.
That is if you do not mean that class A only has Children of class A and so on. That would be doable.
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;
精彩评论