保持可变对象始终在TreeSet中排序

aps*_*aps 11 java treeset

我注意到,如果稍后更改对象属性值,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 + "]";
    }   
}
Run Code Online (Sandbox Code Playgroud)

输出是:

[Student [age=10], Student [age=15], Student [age=30], Student [age=50]]
[Student [age=24], Student [age=15], Student [age=30], Student [age=50]]
Run Code Online (Sandbox Code Playgroud)

在我更改特定学生的年龄,然后打印TreeSet后,Set似乎不再按排序顺序排列.为什么会这样?以及如何保持它总是排序?

aio*_*obe 12

为什么会这样?

因为该集合无法监视其所有对象的更改......它将如何能够做到这一点?!

出现同样的问题HashSets.HashSet保存对象时,无法更改影响对象哈希码的值.

以及如何保持它总是排序?

您通常从集合中删除元素,修改它,然后重新插入它.换句话说,改变

s.age = 24;      //Here I change the age of a student in the TreeSet
Run Code Online (Sandbox Code Playgroud)

至

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

您还可以使用例如列表,并Collections.sort在每次修改对象时调用列表.

  • 删除/重新插入可能会更快(O(log n)而不是O(n log n)). (2认同)

Bal*_*usC 7

您可以使用观察者模式.让你的TreeSet工具Observer让你Student延伸Observable.您需要做的唯一更改是age通过封装隐藏字段,以便您可以对更改进行更多内部控制.

这是一个启动示例:

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);
    }

}
Run Code Online (Sandbox Code Playgroud)

和

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 + "]";
    }
}
Run Code Online (Sandbox Code Playgroud)

现在做一个new ObservableTreeSet而不是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();
    }
});
Run Code Online (Sandbox Code Playgroud)

乍一看是丑陋的,但最终主要代码没有变化.只做一个s.setAge(24)和TreeSet意志"重新排序"自己.