为什么 Treeset<Object> contains() return false 即使 Object.equals() 和 Object.compareTo() 是一致的?

Why does Treeset<Object> contains() return false even if Object.equals() and Object.compareTo() are consistent?

我使用 TreeSet 对我正在开发的游戏引擎中的 Task 对象进行排序。我在Task中写了compareTo()方法,在我的自定义Comparator中写了compare()方法(只是为了尝试,因为它returns [=18=的值]) 然后我写了 equals()(再次尝试)。

...
Treeset set;
Task t;
...
System.out.println(t.compareTo(set.first()));
System.out.println(set.comparator().compare(t, set.first()));
System.out.println(t.equals(set.first()));
System.out.println(String.valueOf(set.contains(t)));

如果我运行这个代码我得到这个输出:

0
0
true
false

我没有考虑到什么?

编辑:这里是 类。我 运行 输出测试而不是调用 queue.remove(t)

class TaskQueue {
    private double taskTime;
    private TreeSet<TimedTask> queue;
    private ArrayList<TimedTask> toAddBuffer;

    public TaskQueue(double taskTime) {
        this();
        this.taskTime = taskTime;
    }

    public TaskQueue() {
        queue = new TreeSet<>(new Comparator<TimedTask>(){
            @Override
            public int compare(TimedTask o1, TimedTask o2) {
                return o1.compareTo(o2);
            }
            
        });
        toAddBuffer = new ArrayList<>();
    }

    public double getTaskTime() {
        return taskTime;
    }

    public void setTaskTime(double taskTime) {
        double delay = taskTime - this.taskTime;
        this.taskTime = taskTime;
        for (TimedTask t : queue) {
            t.setTimeStamp(t.getTimeStamp() + delay);
        }
    }

    public void add(TimedTask t) {
        toAddBuffer.add(t);
    }

    private void add(TimedTask t, double millisecondDelay) {
        t.setTimeStamp(t.getTimeStamp() + (millisecondDelay * (Game.TIME_SCALE)));
        queue.add(t);
    }

    public void performTasks(double timestamp) {
        for (TimedTask task : toAddBuffer) {
            task.setTimeStamp(taskTime + task.getMilliseconds() * (Game.TIME_SCALE / 1000));
            queue.add(task);
        }
        toAddBuffer.clear();
        ArrayList<TimedTask> toRemoveBuffer = new ArrayList<>();
        TimedTask taskToAdd = null;
        boolean scheduledNew;
        do {
            scheduledNew = false;
            for (TimedTask t : queue) {
                if (timestamp < t.getTimeStamp()) {
                    taskTime = timestamp;
                    break;
                }
                t.perform();
                toRemoveBuffer.add(t);
                if (t.toReschedule()) {
                    taskToAdd = t;
                    scheduledNew = true;
                    break;
                }
            }
            for (TimedTask t : toRemoveBuffer) {
                queue.remove(t);
            }
            toRemoveBuffer.clear();
            if (taskToAdd != null) {
                add(taskToAdd, taskToAdd.getMilliseconds());
                taskToAdd = null;
            }
        } while (scheduledNew);
    }
}

public abstract class TimedTask extends Task implements Comparable<TimedTask> {

    private double timeStamp;
    private double milliseconds;
    private boolean reschedule;

    public TimedTask(double delay) {
        this.milliseconds = delay;
    }

    double getTimeStamp() {
        return timeStamp;
    }

    void setTimeStamp(double timeStamp) {
        this.timeStamp = timeStamp;
    }

    public boolean toReschedule() {
        if (milliseconds == 0.0) {
            return false;
        }
        return reschedule;
    }

    public void setToReschedule(boolean toReschedule) {
        reschedule = toReschedule;
    }

    public double getMilliseconds() {
        return milliseconds;
    }

    public void setMilliseconds(double milliseconds) {
        this.milliseconds = milliseconds;
    }

    @Override
    public final int compareTo(TimedTask t) {
        if (this == t) {
            return 0;
        }
        if (timeStamp < t.timeStamp) {
            return -1;
        }
        return 1;
    }

    @Override
    public boolean equals(Object o) {
        if (o == null) {
            return false;
        }
        if (!this.getClass().equals(o.getClass()))
        
            return false;

        TimedTask that = (TimedTask) o;
        return this.compareTo(that) == 0;
    }
}
@Override
public final int compareTo(TimedTask t) {
    if (this == t) {
        return 0;
    }
    if (timeStamp < t.timeStamp) {
        return -1;
    }
    return 1;
}

这是完全错误的。它可以是 - 在你的例子中 - timeStamp == t.timeStampthis != t.

改为写

@Override
public final int compareTo(TimedTask t) {
    return Integer.compare(timeStamp, t.timeStamp);
}

您必须覆盖方法 hashCodeequals。如果您不知道如何实现在堆栈上查找或 google 它。

中包含检查方法hashCode,如果为假,则equals

您对 compareTo 的实施是错误的。

if (this == t) {
    return 0;
}

此检查对象是否与比较相同。

Foo foo1 = new Foo();
Foo foo2 = new Foo();
bollean result = foo1 == foo2;

以上总是错误的,因为 foo1 和 foo2 不是同一个对象。是平等的,但不一样。 总之 double 不是比较好的类型。更好的是使用 BigDecimal.