Выравнивание общего дерева Java - PullRequest
1 голос
/ 07 октября 2011

У меня есть интерфейс для моделей, которые могут иметь родителей и детей

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 Ответ

2 голосов
/ 07 октября 2011

Прежде всего, кажется, существует концептуальная проблема:

Будучи HierarchyAware некоторого базового класса, предотвращает получение потомков производных классов во время компиляции (getChildren).Поэтому безопасно получать список производного класса всегда небезопасно.

То есть, если вы не имеете в виду, что в классе 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;
...