java Set 集合的 contains 方法如何工作
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17104313/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How contains method of Set collection works
提问by user2485224
Hi i am new to java as i know set collection doesn't take duplicate and its contains method should return true when element is already present in collection. I am trying to run below program but i am getting unexpected result.
嗨,我是 Java 新手,因为我知道 set 集合不会重复,并且当集合中已经存在元素时,它的 contains 方法应该返回 true。我试图在程序下面运行,但我得到了意想不到的结果。
public class UserDefinedName {
private final String first, last;
public UserDefinedName(String first, String last) {
this.first = first;
this.last = last;
}
public boolean equals(Object o) {
if (!(o instanceof UserDefinedName))
return false;
UserDefinedName n = (UserDefinedName) o;
return n.first.equals(first) && n.last.equals(last);
}
public static void main(String[] args) {
Set<UserDefinedName> s = new HashSet<UserDefinedName>();
s.add(new UserDefinedName("Carballo", "Videl"));
System.out.println(s.contains(new UserDefinedName("Carballo", "Videl")));
}
}
i am expecting output truebut program prints false. what i am doing wrong?
我期待输出true但程序打印false。我在做什么错?
回答by Vipul
form java doc
形成java文档
If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.
如果根据 equals(Object) 方法两个对象相等,则对两个对象中的每一个调用 hashCode 方法必须产生相同的整数结果。
If hashCode() method is not override then Object's hashCode() method is used which is default implementation.
如果未覆盖 hashCode() 方法,则使用对象的 hashCode() 方法,这是默认实现。
in your case you have override equals method but you use default implementation of hashCode() as you didnt override hashCode() method in your UserDefinedName class.
在您的情况下,您已经覆盖了 equals 方法,但是您使用了 hashCode() 的默认实现,因为您没有覆盖 UserDefinedName 类中的 hashCode() 方法。
The UserDefinedName class overrides the equals method, and the hashCode contract demands that equal objects have equal hash codes. To fulfill this contract, you must override hashCode whenever you override equals
UserDefinedName 类覆盖了 equals 方法,hashCode 契约要求相等的对象具有相等的哈希码。为了履行这个契约,你必须在你覆盖 equals 时覆盖 hashCode
add following code and it will work.
添加以下代码,它将起作用。
public int hashCode() {
return 37 * first.hashCode() + last.hashCode();
}
回答by Alexis C.
Because an hashSet
uses the hashcode value of the object to store it. So it requires that you have to override the method hashCode in your own class. Since you didn't override it, it uses the hashCode method inherited from the object class.
因为 anhashSet
使用对象的 hashcode 值来存储它。所以它要求你必须在你自己的类中覆盖方法 hashCode。由于您没有覆盖它,它使用从对象类继承的 hashCode 方法。
The hashcode from the object class is calculated with the memory address of your object, i.e :
对象类的哈希码是用对象的内存地址计算的,即:
UserDefinedName p = new UserDefinedName("Carballo", "Videl");
System.out.println(p);
System.out.println(0x1e5e2c3);
System.out.println(p.hashCode());
Output :
输出 :
UserDefinedName@1e5e2c3
31843011
31843011
So if you tried this, you will see that it outputs true :
所以如果你试过这个,你会看到它输出 true :
Set<UserDefinedName> s = new HashSet<UserDefinedName>();
UserDefinedName p = new UserDefinedName("Carballo", "Videl");
s.add(p);
System.out.println(s.contains(p));
Now if you want to compare your User class correclty, you will have to override your hashCode
method (you can generated it with eclipse) to generate the hashCode
your object field by field.
现在,如果您想比较 User 类的正确性,则必须覆盖您的hashCode
方法(您可以使用 eclipse 生成它)以hashCode
逐个字段生成您的对象。
If you have this method to your class, this will print true for the code you provide.
如果你的类有这个方法,这将为你提供的代码打印 true。
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((first == null) ? 0 : first.hashCode());
result = prime * result + ((last == null) ? 0 : last.hashCode());
return result;
}
回答by Prasad Kharkar
When you are overriding equals method, then always override hashcode method also. A simple rule is, if two objects are considered to be equal then they should return the same hashcode.
当您覆盖 equals 方法时,也始终覆盖 hashcode 方法。一个简单的规则是,如果两个对象被认为是相等的,那么它们应该返回相同的哈希码。
I took your code and generated equals and hashcode with the help of eclipse
我在 eclipse 的帮助下获取了你的代码并生成了 equals 和 hashcode
import java.util.HashSet;
import java.util.Set;
public class UserDefinedName {
private final String first, last;
public UserDefinedName(String first, String last) {
this.first = first;
this.last = last;
}
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((first == null) ? 0 : first.hashCode());
result = prime * result + ((last == null) ? 0 : last.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
UserDefinedName other = (UserDefinedName) obj;
if (first == null) {
if (other.first != null)
return false;
} else if (!first.equals(other.first))
return false;
if (last == null) {
if (other.last != null)
return false;
} else if (!last.equals(other.last))
return false;
return true;
}
public static void main(String[] args) {
Set<UserDefinedName> s = new HashSet<UserDefinedName>();
s.add(new UserDefinedName("Carballo", "Videl"));
System.out.println(s.contains(new UserDefinedName("Carballo", "Videl")));
UserDefinedName obj1 = new UserDefinedName("prasad", "kharkar");
UserDefinedName obj2 = new UserDefinedName("prasad", "kharkar");
System.out.println(obj1.equals(obj2));
System.out.println(obj1.hashCode());
System.out.println(obj2.hashCode());
}
}
the output is
输出是
true
true
-1072813416
-1072813416
回答by Arnab Biswas
Along with equals, you need to implement hashcode() method also.
除了 equals 之外,您还需要实现 hashcode() 方法。
HashSet is a data structure which uses HashMap internally. In a HashMap objects are stored in key value pairs. But, HashSet only accepts key, the corresponding value being an empty dummy object (This is ofcourse taken care by JVM). Now, for this hashing mechanism to work properly you need to implement equals() as well as hashCode() method. According to the JDK documentation:
HashSet 是一种内部使用 HashMap 的数据结构。在 HashMap 中,对象存储在键值对中。但是,HashSet 只接受键,对应的值是一个空的虚拟对象(这当然是由 JVM 处理的)。现在,要使这种散列机制正常工作,您需要实现 equals() 和 hashCode() 方法。根据JDK 文档:
This class implements the Set interface, backed by a hash table (actually a HashMap instance). It makes no guarantees as to the iteration order of the set; in particular, it does not guarantee that the order will remain constant over time. This class permits the null element.
This class offers constant time performance for the basic operations (add, remove, contains and size), assuming the hash function disperses the elements properly among the buckets. Iterating over this set requires time proportional to the sum of the HashSet instance's size (the number of elements) plus the "capacity" of the backing HashMap instance (the number of buckets).
这个类实现了 Set 接口,由一个哈希表(实际上是一个 HashMap 实例)支持。它不保证集合的迭代顺序;特别是,它不保证订单会随着时间的推移保持不变。此类允许空元素。
这个类为基本操作(添加、删除、包含和大小)提供恒定的时间性能,假设散列函数在桶中正确地分散元素。迭代这个集合需要的时间与 HashSet 实例的大小(元素数)加上支持 HashMap 实例的“容量”(桶数)的总和成正比。
You might like to check "Effective Java- Second Edition - Chapter Three - Methods common to all objects". That will give you a clear understanding about the best practices of implementing equals() and hashCode() methods.
您可能想查看“Effective Java- 第二版 - 第三章 - 所有对象通用的方法”。这将使您清楚地了解实现 equals() 和 hashCode() 方法的最佳实践。
回答by Mubin
HashSet
needs both hashCode
and equals
method to be overridden.
HashSet
需要同时覆盖hashCode
和equals
方法。