我最初是为了测试基于理论,最佳实践的问题,我想在这里问一下,但在这个过程中我在java.Set类中发现了一些有趣的行为。最初,我想知道这种方法的任何潜在缺陷,但现在我可以看到它根本不起作用,我想知道原因。
我有一些对象是我的应用程序的数据库对象的容器。这些对象都具有唯一的integer id
,hashCode()
和equals()
由整数ID定义(用于存储在散列集中)。
好吧,我希望能够检查一个hashset是否包含只给出id的对象。 当然,我可以创建一个新的对象实例并检查这种方式。但是,只是为了踢,我想看看我是否能够完成它。当然,这对于一个hashmap来说也是微不足道的,所以这真的不是一个重要的问题,仅仅是为了娱乐和知识。
所以,我创建了一个类,并尝试在contains()
上调用integer
,而不是该对象的实例。当然,Netbeans为这个
Suspicious call to java.util.Collection.contains:
Given object cannot contain instances of int (expected Person)
忽略错误并运行代码,我很震惊地发现 Java甚至没有调用equals方法。我在我的equals方法中调试System.out.println()
以进行验证,并且是的,它甚至没有被召唤。
在下面发布的代码中,预期的输出应该是(如果我的理论 正确 ):
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");
}
}
答案 0 :(得分:5)
这是因为比较是在提供的对象上完成的而不是集合中的元素。来自HashSet#contains(Object):
如果此set包含指定的元素,则返回true。更正式地说,当且仅当此集合包含元素e以使(o == null?e == null:o.equals(e))时才返回true。
因此,在您的示例中,您将进行比较,如 integer.equals(person)
。因此,如果您的集合包含Person
个对象,则永远不会检查if(obj instanceof Integer)
条件,但如果您的集合包含Integer
个对象,则会满足该条件,因此会进行检查。