我最初开始这个是为了测试一个基于理论的最佳实践问题,我想在这里问这个问题,但在这个过程中我发现了 java.Set 类中的一些有趣行为。最初,我想知道这种方法的任何潜在缺陷,但现在我发现它根本不起作用,我想知道为什么。
我有一些对象是我的应用程序数据库对象的容器。所有对象都有唯一的整数 id
,hashCode()
和 equals()
由整数 id 定义(用于存储在哈希集中).
好吧,我想要检查哈希集是否包含仅给定 id 的对象的能力。 当然,我可以创建对象的新实例并以这种方式进行检查。但是,只是为了好玩,我想看看我是否能完成它。当然,这对于 HashMap 来说也是微不足道的,所以这真的不是一个重要的问题,只是为了好玩和知识。
因此,我创建了一个类,并尝试在 integer
上调用 contains()
,而不是对象的实例。当然,Netbeans 对此给出了一个有趣的警告
Suspicious call to java.util.Collection.contains:
Given object cannot contain instances of int (expected Person)
忽略错误并运行代码,我震惊地发现Java甚至没有调用equals方法。我调试了System.out.println()
s 在我的 equals 方法中进行验证,是的,它甚至没有被调用。
在下面发布的代码中,预期输出应该是(如果我的理论正确):
Here Yes Here Yes
或者(如果我的理论不正确):
Here Yes Here No
但是,输出是:
Here Yes No
注意,在“No”之前没有“Here”,证明甚至没有调用 equals 方法。
任何人都可以阐明吗?我总是被告知要将此添加到 equals()
以提高效率:
if (!(obj instanceof Person))
return false;
但如果在这种情况下甚至不调用 equals()
,那将毫无意义。
这是 SSCCE:
感谢您的宝贵时间。
import java.util.LinkedHashSet;
import java.util.Set;
/**
*
* @author Ryan
*/
public class Test7 {
public static void main(String[] args) {
class Person {
public final int id;
public final String name;
public Person(int id, String name) {
this.id = id;
this.name = name;
}
@Override
public boolean equals(Object obj) {
System.out.println("Here");
if (this == obj)
return true;
if (obj instanceof Person)
return id == ((Person)obj).id;
else if(obj instanceof Integer)
return id == (Integer)obj;
else {
System.out.println("Returning False");
return false;
}
}
@Override
public int hashCode() {
return id;
}
}
Set<Person> set = new LinkedHashSet<Person>();
set.add(new Person(1, "Bob"));
set.add(new Person(2, "George"));
set.add(new Person(3, "Sam"));
if(set.contains(new Person(1, "Bob")))
System.out.println("Yes");
else
System.out.println("No");
if(set.contains(1))
System.out.println("Yes");
else
System.out.println("No");
}
}
最佳答案
这是因为比较是在提供的对象上完成的,而不是集合中的元素。来自 HashSet#contains(Object) :
Returns true if this set contains the specified element. More formally, returns true if and only if this set contains an element e such that (o==null ? e==null : o.equals(e)).
所以在您的示例中,您将进行类似 integer.equals(person)
的比较。因此,如果您的集合包含 Person
对象,则永远不会检查 if(obj instanceof Integer)
条件,但如果您的集合包含 Integer
对象,该条件将得到满足,因此将被检查。
关于java - 奇怪的 Set.contains() 行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16888756/