有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java排序ObservableList时引发的更改通知数

我在玩JavaFX时,偶然发现了Oracle的Using JavaFX Collections教程,并遇到了一个问题。在示例1-6中,他们使用FXCollectionsObservableList进行排序:

List<String> list = new ArrayList<String>();
list.add("d");
list.add("b");
list.add("a");
list.add("c");

ObservableList<String> observableList = FXCollections.observableList(list);
observableList.addListener(new ListChangeListener() {
    @Override
    public void onChanged(ListChangeListener.Change change) {
        System.out.println("Detected a change! ");
    }
});

FXCollections.sort(observableList); // one notification, as expected
// Collections.sort(observableList); // also only one notification. why?

根据本教程,仅打印一个更改通知。本教程提到,当使用Collections.sort()而不是FXCollections.sort()时,将有四个更改通知,但我仍然只收到一个。你知道为什么吗?需要做什么才能获得四个更改通知


共 (1) 个答案

  1. # 1 楼答案

    SortableListAPI(似乎无法在线找到javadoc):

    SortableList is a list that can sort itself in an efficient way, in contrast to the Collections.sort() method which threat all lists the same way. E.g. ObservableList can sort and fire only one notification.

    基本上:

    • ObservableList上调用FXCollections.sort,它是SortableList的后代
    • FXCollections.sortObservableList强制转换为SortableList,并调用((SortableList<? extends T>)list).sort();
    • 具体类型似乎是com.sun.javafx.collections.ObservableListWrapper
    • 反过来,该操作声称在排序时仅触发1通知

    注意(I):JDK8u45的源代码FXCollections.sort这里

    /**
     * Sorts the provided observable list.
     * Fires only <b>one</b> change notification on the list.
     * @see Collections#sort(java.util.List)
     */
    @SuppressWarnings("unchecked")
    public static <T extends Comparable<? super T>> void sort(ObservableList<T> list) {
        if (list instanceof SortableList) {
            ((SortableList<? extends T>)list).sort(); // here's what happens
        } else {
            List<T> newContent = new ArrayList<T>(list);
            Collections.sort(newContent);
            list.setAll((Collection<T>)newContent);
        }
    }
    

    注(二)的来源ObservableListWrapper.sort

    @Override
    public void sort(Comparator<? super E> comparator) {
        if (backingList.isEmpty()) {
            return;
        }
        int[] perm = getSortHelper().sort(backingList, comparator);
        // here's the single change fired
        fireChange(new SimplePermutationChange<E>(0, size(), perm, this));
    }
    

    如您所见,fireChange调用在实际执行排序后触发一次

    更新

    {}习惯用法调用{}。 在Java8中,List.sort实际上有一个default实现,但是这里没有使用它,因为它被重写了,所以现有的机制仍然来自ObservableListWrapper

    TL;DR

    我怀疑是否有任何优雅的方法可以获得与对List进行排序所需的操作数一样多的通知,除非您使用自己的ObservableList实现

    快速把戏(在Java 8中测试)

    我刚刚发现了一个触发多个Changed事件的技巧

    如果您使用以下习惯用法:

    Collections.sort(observableList.subList(0, observableList.size()));

    原因是subList将返回一个List,因此将使用default{}