13

オブジェクトの属性値が後で変更された場合、TreeSet は変更可能なオブジェクトをソートされた順序で保持しないことに気付きました。例えば、

public class Wrap { 
    static TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>(){
        @Override
        public int compare(Student o1, Student o2) {            
            return o1.age - o2.age;
        }       
    }); 
    public static void main(String []args){
        Student s = new Student(10);
        ts.add(s); 
        ts.add(new Student(50));
        ts.add(new Student(30));
        ts.add(new Student(15));
        System.out.println(ts);
        s.age = 24;      //Here I change the age of a student in the TreeSet
        System.out.println(ts);     
    }
}
class Student{
    int age;
    Student(int age){
        this.age = age;
    }   
    @Override
    public String toString() {
        return "Student [age=" + age + "]";
    }   
}

出力は次のとおりです。

[Student [age=10], Student [age=15], Student [age=30], Student [age=50]]
[Student [age=24], Student [age=15], Student [age=30], Student [age=50]]

特定の生徒の年齢を変更して TreeSet を印刷すると、セットがソートされていないように見えます。なぜこれが起こるのですか?そして、それを常にソートしておく方法は?

4

6 に答える 6

13

なぜこれが起こるのですか?

セットはすべてのオブジェクトの変更を監視することはできないため.どうすればそれを行うことができるでしょうか?!

についても同様の問題が発生しHashSetsます。HashSetがオブジェクトを保持している場合、オブジェクトのハッシュ コードに影響する値を変更することはできません。

そして、それを常にソートしておく方法は?

通常、セットから要素を削除し、変更してから、再度挿入します。つまり、変更

s.age = 24;      //Here I change the age of a student in the TreeSet

ts.remove(s);
s.age = 24;      //Here I change the age of a student in the TreeSet
ts.add(s);

たとえば、リストを使用してCollections.sort、オブジェクトを変更するたびにリストを呼び出すこともできます。

于 2011-11-06T20:13:39.297 に答える
9

オブザーバー パターンを利用できます。TreeSet実装して拡張Observerさせてください。行う必要がある唯一の変更は、カプセル化によってフィールドを非表示にして、変更に対する内部制御を強化することです。StudentObservableage

キックオフの例を次に示します。

public class ObservableTreeSet<O extends Observable> extends TreeSet<O> implements Observer {

    public ObservableTreeSet(Comparator<O> comparator) {
        super(comparator);
    }

    @Override
    public boolean add(O element) {
        element.addObserver(this);
        return super.add(element);
    }

    @Override
    @SuppressWarnings("unchecked")
    public void update(Observable element, Object arg) {
        remove(element);
        add((O) element);
    }

}

public class Student extends Observable {

    private int age;

    Student(int age) {
        this.age = age;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        if (this.age != age) {
            setChanged();
        }

        this.age = age;

        if (hasChanged()) {
            notifyObservers();
        }
    }

    @Override
    public String toString() {
        return "Student [age=" + age + "]";
    }
}

new ObservableTreeSetの代わりにaを実行しnew TreeSetます。

static TreeSet<Student> ts = new ObservableTreeSet<Student>(new Comparator<Student>() {
    @Override
    public int compare(Student o1, Student o2) {
        return o1.getAge() - o2.getAge();
    }
});

一見醜いですが、メイン コードに変更はありません。s.setAge(24)aを実行するだけで、TreeSetそれ自体が「並べ替え」られます。

于 2011-11-06T20:31:19.847 に答える
1

これは、マップとセットの一般的な問題です。値は、挿入時に hashCode/equals/compare を使用して挿入されます。これらのメソッドが基づいている値が変更されると、構造が台無しになる可能性があります。

1 つの方法は、セットからアイテムを削除し、値が変更された後に再度追加することです。それなら正解でしょう。

于 2011-11-06T20:14:43.690 に答える
0

Glazed Lists が役に立ちます: http://www.glazedlists.com/

EventList に使用していますが、並べ替えは試していません。しかし、ホームページには主な機能がリストされています。

ライブ ソートとは、データが変更されてもテーブルがソートされたままになることを意味します。

于 2015-02-04T16:30:59.817 に答える
0

TreeSet問題が反復順序であり、 (headSet()など)の余分な機能を使用したくない場合はHashSet、カスタム反復子を使用します。また、あなたの例には大きな問題があります。同じ年齢の 2 人の学生 (多くの場合発生します) が衝突します。

考えられる解決策:

public class Main {

    public static void main(final String[] args) {
        MagicSet<Student> ts = new MagicSet<Student>(new Comparator<Student>() {

            @Override
            public int compare(Student student1, Student student2) {
                return student1.age - student2.age;
            }

        });

        Student s = new Student(10);

        ts.add(s); 
        ts.add(new Student(50));
        ts.add(new Student(30));
        ts.add(new Student(15));

        System.out.println(ts); // 10, 15, 30, 50
        s.age = 24;
        System.out.println(ts); // 15, 24, 30, 50
    }

    public static class Student {

        public int age;

        public Student(int age) {
            this.age = age;
        }

        @Override
        public String toString() {
            return "Student [age=" + age + "]";
        }

    }

    public static class MagicSet<T> extends HashSet<T> {

        private static final long serialVersionUID = -2736789057225925894L;

        private final Comparator<T> comparator;

        public MagicSet(Comparator<T> comparator) {
            this.comparator = comparator;
        }

        @Override
        public Iterator<T> iterator() {
            List<T> sortedList = new ArrayList<T>();
            Iterator<T> superIterator = super.iterator();
            while (superIterator.hasNext()) {
                sortedList.add(superIterator.next());
            }
            Collections.sort(sortedList, comparator);
            return sortedList.iterator();
        }

    }

}
于 2016-08-10T20:14:07.990 に答える