【发布时间】:2016-06-14 10:59:24
【问题描述】:
您好,我可能监督了一些事情,但它就是这样。
我有一个TreeSet<CustomObject>,我不想在 Set 中有重复项。我的CustomObject 类看起来像这样。
class CustomObject implements Comparable<CustomObject> {
String product;
String ean;
public CustomObject(String ean){
this.ean = ean;
// product is getting set via setter and can be null
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
CustomObject that = (CustomObject) o;
return ean.equals(that.ean);
}
@Override
public int hashCode() {
return ean.hashCode();
}
@Override
public int compareTo(CustomObject another) {
if(equals(another)) return 0;
if(product != null && another.product == null) return -1;
if(product == null) return 1;
return product.compareToIgnoreCase(another.product);
}
}
现在我有一个新对象的添加函数。
private final TreeSet<CustomObject> productCatalog;
public void addObject(SomeData tag) {
CustomObject p = new CustomObject(tag.getEan());
if (productCatalog.contains(p)) { // <-- This checks only one entry of the Set.
for (CustomObject temp : productCatalog) {
if (temp.equals(p)) {
p = temp; // I do stuff with that later which is irrelevent here
}
}
} else {
productCatalog.add(p);
}
}
方法productCatalog.contains(p) 从Comparable 接口调用compareTo 方法并进行比较。这里的问题是它实际上只检查我认为最后一个对象?在集合中。所以发生的情况是只存在一个唯一的 CustomObject 条目。
这是我使用调试器跟踪它时的场景:
productCatalog.contains(p)- 致电
compareTo - 调用
equals检查ean.equals(that.ean) - 一次返回真,但每隔一次返回假。因为它只检查最后一个对象
如何让它不仅检查第 4 步中的一个对象,而且检查集合中的所有当前对象。我错过了什么?
谢谢!
编辑:这些是一些示例数据。为简单起见,SomeData tag 基本上是一个字符串。
First run:
addObject("Ean1") // success added
addObject("Ean2") // success added
addObject("Ean3") // success added
addObject("Ean4") // success added
所有内容都被添加到 TreeSet 中。
Second run:
addObject("Ean1") // failed already in the map
addObject("Ean2") // failed already in the map
addObject("Ean3") // failed already in the map
addObject("Ean5") // success added
addObject("Ean4") // success added
addObject("Ean4") // success added
出于测试目的,我根据字符串 ean 手动设置产品名称。
public CustomObject(String ean){
this.ean = ean;
switch(ean){
case "Ean1": product = "TestProduct"; break;
case "Ean2": product = "ProductTest";break;
case "Ean3": product = "Product";break;
}
TreeSet 充当缓存。
Edit2:我就是这样解决的。
for (CustomObject temp : productCatalog) {
if (temp.equals(p)) {
p = temp; // I do stuff with that later which is irrelevent here
}
}
我使用 contains 方法删除了 if 语句,因为 TreeSet 使用 compareTo() 来检查 Set 中的每个元素,所以它总是会返回 ´1or-1in my special case. Now I simply iterate over the Set to correctly use theequals` 方法。
Java Docs 声明如下
请注意,由集合维护的顺序(无论是否显式 提供了比较器)必须与equals一致,如果它是 正确实现 Set 接口。 (见可比较或比较 用于与等于一致的精确定义。)就是这样 因为 Set 接口是根据 equals 操作定义的, 但是 TreeSet 实例使用它的执行所有元素比较 compareTo(或比较)方法,因此两个元素被视为相等 通过这种方法,从集合的角度来看,它们是相等的。这 一个集合的行为是明确定义的,即使它的顺序是不一致的 等于;它只是不遵守集合的一般合同 界面。
【问题讨论】:
-
您能否更具体地说明您遇到的错误行为类型?集合中实际上是否存在“双重元素”? “最后一个对象”是什么意思?
标签: java set comparable