有一个java bean Car可能包含两个值:model和price。
现在假设我以这种方式覆盖equals()和hashcode()只检查模型:
public boolean equals(Object o) {
return this.model.equals(o.model);
}
public int hashCode() {
return model.hashCode();
}
这允许我检查一个arraylist是否已经包含相同型号的商品Car(并且价格无关紧要),这样:
List<Car> car = new ArrayList<Car>();
car.add(new Car("carA",100f));
car.add(new Car("carB",101f));
car.add(new Car("carC",110f));
System.out.println(a.contains(new Car("carB",111f)));
返回TRUE。那没关系,因为车已经存在了!
但现在我认为ArrayList不好,因为我想维护订购的项目,所以我用这样的方式用TreeSet替换它:
Set<Car> car = new TreeSet<Car>(new Comparator<Car>() {
@Override
public int compare(Car car1, Car car2) {
int compPrice = - Float.compare(car1.getPrice(), car2.getPrice());
if (compPrice > 0 || compPrice < 0)
return compPrice;
else
return car1.getModel().compareTo(car2.getModel());
}});
car.add(new Car("carA",100f));
car.add(new Car("carB",101f));
car.add(new Car("carC",110f));
System.out.println(a.contains(new Car("carB",111f)));
但是现在有一个问题,它返回FALSE ...为什么?
似乎当我使用arrayList调用contains()时,调用equals()方法。 但似乎当我使用带有比较器的TreeSet调用contains()时,会使用比较器。
为什么会这样?
答案 0 :(得分:3)
隐式排序TreeSet
,并使用Comparator
进行此排序。 equals()
方法只能告诉您两个对象是相同还是不同,而不是如何排序它们进行排序。只有Comparator
可以做到这一点。
更重要的是,TreeSet
还使用了搜索的比较。这是基于树的地图/集的整点。调用contains()
方法时,将执行二进制搜索,并根据比较器的定义方式找到或找不到目标。比较器不仅定义逻辑顺序而且定义逻辑标识。如果您依赖于由不一致的equals()
实现定义的逻辑身份,则可能会出现混淆。
答案 1 :(得分:3)
TreeSet
形成一个二叉树,根据自然(或非)顺序保留元素,因此为了快速搜索一个特定元素是集合,TreeSet
使用Comparable
或{{ 1}}而不是Comparator
。
作为TreeSet JavaDoc精确:
注意由一组维护的排序(无论是否显式 比较器提供)必须与equals一致,如果是的话 正确实现Set接口。 (参见可比较者或比较者 对于与equals一致的精确定义。)就是这样 因为Set接口是根据equals操作定义的, 但是TreeSet实例使用它执行所有元素比较 compareTo(或compare)方法,因此两个被认为相等的元素 从该集合的角度来看,通过这种方法是相等的。该 集合的行为即使其排序不一致也是明确定义的 与...平等它只是没有遵守集合的一般合同 接口
我们可以找到与HashCode / Equals合同的相似性:
如果equals()
返回equals()
,true
必须也会返回true,以便在搜索过程中找到。
与hashcode()
相同:
如果TreeSet
(使用contains()
或Comparator
)返回Comparable
,true
必须返回{{ 1}}也是为了与equals()
一致。
因此: true
方法中使用的字段必须与equals()
实施中的字段完全相同(不多,不少)。
答案 2 :(得分:0)
不同行为的原因是,您在compare方法中考虑price成员,但在equals中忽略它。
new Car("carB",101f) // what you add to the list
new Car("carB",111f) // what you are looking for
两个实例都是“等于”(抱歉......),因为他们的模型成员是相同的(并且在该测试之后实现停止)。但是,它们“比较”不同,因为 实现也会检查价格成员。