[英]what happen when override hashcode()
I have some dilemma about hashcodes. 我对散列码有些困惑。 As I know Object class hashcode represent the memory location of any object and for every object(distinct objects) this hashcode is unique.
据我所知,对象类哈希码表示任何对象的内存位置,并且对于每个对象(不同的对象),此哈希码都是唯一的。 Ok, this point is very much straight forward.
好的,这很简单。
But in case of hashing(HashSet, HashMap etc), we need to override hashcode and equals method. 但是在哈希(HashSet,HashMap等)的情况下,我们需要重写哈希码和equals方法。 Now in this case hashcode will represent the bucket location.
现在,在这种情况下,哈希码将代表存储桶位置。 Now I have few question:
现在我有几个问题:
For example I am taking Student
class and I override hashcode() method of Student class.. 例如,我上了
Student
类,并且重写了Student类的hashcode()方法。
class Student{
//
int id;
@override
int hashcode(){
return id*31;
}
}
Student stu1 = new Student(1);
Student stu2 = new Student(1);
If I create two same Student objects(stu1, stu2) which are returning similar hashcode. 如果我创建两个相同的Student对象(stu1,stu2),它们返回相似的哈希码。 So if we add these two objects in hashset, it will call it's hashcode and get the bucket location but what will happen with real student(two similar objects that we created) object?
因此,如果我们将这两个对象添加到哈希集中,它将调用它的哈希码并获取存储桶位置,但是真正的student(我们创建的两个类似对象)对象会发生什么? Means what will be it's memory location in heap?
意味着它将是堆中的内存位置? Are both pointing to same heap location?
两者都指向相同的堆位置吗?
HashCode never determines the location in heap. HashCode永远不会确定堆中的位置。 Both equals and hashcode is used to compare equality of objects, primarily inside hash based collections such as Hashtable and HashMap.
equals和hashcode都用于比较对象的相等性,主要是在基于哈希的集合(例如Hashtable和HashMap)内部。
(There is absolutely no way to find out the memory location.) (绝对没有办法找出内存位置。)
As you know Set
implements equals()
and hashcode()
method, 如您所知
Set
实现了equals()
和hashcode()
方法,
hashcode
differs for two object , then there will be two elements in the set hashcode
不同,则集合中将有两个元素 Hashcode
is equal , the second entry replaces the first one . Hashcode
相等,则第二个条目替换第一个条目。 so there will be only one element in the set When two unequal objects have the same hash value, this causes a collision in the hash table, because both objects
want to be in the same slot (bucket). 当两个不相等的对象具有相同的哈希值时,这将导致哈希表发生冲突,因为两个
objects
希望位于同一插槽(存储桶)中。 The hash algorithm must resolve such collisions
. 哈希算法必须解决此类
collisions
。
Student stu1 = new Student(1);
Student stu2 = new Student(1);
When you add stu1
and stu2
into the set with same value into the set
, 当您添加
stu1
和stu2
进入设置与相同的值入set
,
Set<Student> sset=new HashSet<Student >();
sset.add(stu1);
sset.add(stu2);
the set sset
will hold two values with the same values , but both refer to two different objects as their hashcode
is different set
sset
将保存两个具有相同值的值,但由于hashcode
不同,它们都引用两个不同的对象
Hmm...Its not too hard to see whether they share the same memory location. 嗯...不难发现它们是否共享相同的内存位置。 A reference equality test, ie stu1==stu2 will answer that.
参考相等性测试,即stu1 == stu2将回答该问题。 As for the hash, they will fall in the same bucket because they have the same hashcode.So, given that condition, when you try to retrieve the student, the equals method will be used to determine which Student is being looked for.
至于散列,由于它们具有相同的散列码,它们将落在相同的存储桶中。因此,在这种情况下,当您尝试检索学生时,将使用equals方法来确定要查找的学生。 Run the code below.
运行下面的代码。
import java.util.HashSet;
class Student {
//
int id;
Student(int id) {
this.id = id;
}
@Override
public int hashCode() {
return id * 31;
}
public static void main(String[] args) {
Student stu1 = new Student(1);
Student stu2 = new Student(1);
Student stu3 = stu1;
HashSet<Student> hash = new HashSet<Student>();
hash.add(stu1);
hash.add(stu2);
if(stu1==stu2){
System.out.println("Stu1 and stu2 refer to the same
location in memory...");
}
if(stu1==stu3){
System.out.println("Stu1 and stu3 refer to the same
location in memory...");
}
}
}
Object's Hashcode is not a physical memory location of the object located in heap. 对象的哈希码不是位于堆中的对象的物理内存位置。 Its a digest of the data stored in an instance of the class into a single hash value (a 32-bit signed integer).
它是将存储在该类实例中的数据的摘要转换为单个哈希值(32位带符号整数)。 (Source wiki )
(来源Wiki )
But in case of hashing(HashSet, HashMap etc), we need to override hashcode and equals method
Yes, until and unless you're using your class instance as a key in any map implemented classes. 是的,直到并且除非您将您的类实例用作任何地图实现的类的键,除非您使用它。
Now consider your given scenrio : 现在考虑给定的场景:
@override
int hashcode(){
return id*31;
}
Nothing will happen but you end up adding different objects in to your map or set. 什么都不会发生,但是最终您将不同的对象添加到地图或集合中。
There is a contract between object hashcode
and equals
method saying that, when you override equals
you must override hascode()
and vice versa inorder to uniformly distribute the object among the buckets. 对象
hashcode
和equals
方法之间有一个约定,即当您覆盖equals
,必须重写hascode()
,反之亦然,以便将对象均匀分布在存储桶中。
// The worst possible legal hash function - never use!
@Override
public int hashCode() {
return 42;
}
(Source Effective Java)
It's very much legal because it ensures that equal objects have the same hash code. 这是非常合法的,因为它确保相等的对象具有相同的哈希码。 It's atrocious because it ensures that every object has the same hash code.
之所以如此,是因为它确保每个对象都具有相同的哈希码。 Therefore, every object hashes to the same bucket, and hash tables degenerate to linked lists.
因此,每个对象散列到相同的存储桶,并且哈希表退化为链接列表。 Programs that should run in linear time instead run in quadratic time.
应该以线性时间运行的程序改为以二次时间运行。 For large hash tables, this is the difference between working and not working.
对于大型哈希表,这是工作与不工作之间的区别。
For your clarification : 为了您的澄清:
Consider this, Bellow is my class and here I'm defining the contract between equals and hascode saying that two objects having same roll and name must be identical. 考虑到这一点,贝娄是我的班,在这里,我定义了equals和hascode之间的契约,说具有相同滚动和名称的两个对象必须相同。
public class MyClass {
private int roll;
private String name;
private String subject;
public MyClass(int roll, String name, String subject) {
this.roll = roll;
this.name = name;
this.subject = subject;
}
@Override
public boolean equals(Object object) {
boolean result = false;
if (object == null || object.getClass() != getClass()) {
result = false;
} else {
MyClass myclass = (MyClass) object;
if (this.roll == myclass.getRoll()
&& this.name == myclass.getName()) {
result = true;
}
}
return result;
}
@Override
public int hashCode() {
int hash = 17;
hash = 31 * this.roll;
hash = 31 * hash + this.name.hashCode();
return hash;
}
public static void main(String args[]) {
MyClass obj1 = new MyClass(1, "A", "Math");
MyClass obj2 = new MyClass(1, "A", "Phy");
MyClass obj3 = new MyClass(1, "B", "Chem");
System.out.println("obj1.equals(obj2) : "+obj1.equals(obj2)); // true. As both the objects have the same roll & name
System.out.println("obj1 == obj2 : "+(obj1 == obj2)); // false. because two are references of different instance.
Set<MyClass> set = new HashSet<MyClass>();
set.add(obj1);
set.add(obj2);
System.out.println("set :"+set.size()); // 1 object
for(MyClass cls:set){
System.out.println(cls); //i.e [1 A Math]. It'll not replaced by the 2nd one.
}
Map<MyClass,String> map= new HashMap<MyClass,String>();
map.put(obj1,"IN");
map.put(obj2,"US");
System.out.println("map :"+map.size());// 1 object
for (Map.Entry<MyClass, String> entry : map.entrySet()){
System.out.println(entry.getKey() + " : " + entry.getValue()); // [1 A Math : US]. here you may notice the key remains same but the value will be replaced.
}
}
public int getRoll() {
return roll;
}
public String getName() {
return name;
}
public String getSubject() {
return subject;
}
@Override
public String toString(){
return ""+roll+" "+name+" "+subject;
}
} }
Note: Whenever you're creating an object using new
keyword, each time it'll create a different object in the heap no matter the contents in them are same or not. 注意:无论何时使用
new
关键字创建对象,无论对象中的内容相同与否,它每次都会在堆中创建不同的对象。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.