有一个非常简单的 Java 代码示例:
import java.util.*;
class Point implements Comparable<Point>{
float x, y;
Point(float x_, float y_) { x = x_; y = y_; }
int compareTo(Point p_) { println(dist(x, y, p_.x, p_.y)); return dist(x, y, p_.x, p_.y) < 1E-4 ? -1 : 1; }
float dist(float x0_, float y0_, float x1_, float y1_) { return sqrt(pow(x1_ - x0_, 2) + pow(y1_ - y0_, 2)); }
}
public static void main(String[] args){
TreeSet<Point> tp = new TreeSet<Point>();
tp.add(new Point(0.125, 0.5));
tp.add(new Point(0.-125, 0.25));
tp.add(new Point(0.15, -0.75));
tp.add(new Point(0.125, 0.5));
System.out.println(tp);
}
而且我认为每个点都是 unique,同时进行距离检查,如果它低于 epsilon 代码应该删除重复项。
但是,尽管它是第一个条目的副本,但保留第四个条目是行不通的。
我的目的是获得一组 unique 点 (vectors)。
回答1
之所以如此,是因为 Set 接口是根据 equals 操作定义的,但是 TreeSet 实例使用其 compareTo(或 compare)方法执行所有元素比较,因此该方法认为相等的两个元素是,从集合的角度来看,相等。一个集合的行为是明确定义的,即使它的顺序与equals不一致;它只是不遵守 Set 接口的一般约定。
https://docs.oracle.com/javase/7/docs/api/java/util/TreeSet.html
换句话说,TreeSet
类不通过equals
方法保持其元素的唯一性,而是通过类实现的compareTo
方法,如果类实现了Comparable
,或者通过compareTo
的给定的 Comparator
。
正如其他人在评论中指出的那样,如果您想通过坐标保持 Point
之间的唯一性,您应该重写 equals
和 hashCode
方法,就像 https://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#hashCode() 声明并使用 HashSet
到 store 你的 Point
。
在下面的代码片段中,我通过实现 equals
、hashCode
和 toString
方法更新了您的类,以显示如何只打印三个元素而不是四个元素。
public class Point implements Comparable<Point> {
double x, y;
public Point(double x, double y) {
this.x = x;
this.y = y;
}
// ... your implementation ...
@Override
public boolean equals(Object obj) {
if (obj == null) return false;
if (obj == this) return true;
if (obj.getClass() != getClass()) return false;
Point other = (Point) obj;
return x == other.x && y == other.y;
}
@Override
public int hashCode() {
return Objects.hash(x, y);
}
@Override
public String toString() {
return String.format("(%g;%g)", x, y);
}
public static void main(String[] args) {
HashSet<Point> tp = new HashSet<>();
tp.add(new Point(0.125, 0.5));
tp.add(new Point(0. - 125, 0.25));
tp.add(new Point(0.15, -0.75));
tp.add(new Point(0.125, 0.5));
System.out.println(tp);
}
}