简体   繁体   English

覆盖hashcode()时会发生什么

[英]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()方法,

  1. So if the hashcode differs for two object , then there will be two elements in the set 因此,如果两个对象的hashcode不同,则集合中将有两个元素
  2. If 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 , 当您添加stu1stu2进入设置与相同的值入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. 什么都不会发生,但是最终您将不同的对象添加到地图或集合中。

Important Contract : 重要合同:

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. 对象hashcodeequals方法之间有一个约定,即当您覆盖equals ,必须重写hascode() ,反之亦然,以便将对象均匀分布在存储桶中。

Be Carefull !! 小心点 !!

// 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.

相关问题 当您使用super和此关键字调用替代方法时会发生什么? - What happen when you call an override method using super and this keyword? 不执行而覆盖spring仓库方法时会发生什么 - what happen when override spring repository method without implementing HashCode - 如果相同的对象碰巧在同一个桶中散列会发生什么? - HashCode - What will happen if equal object happened to hash in the same bucket? 第9项:“在覆盖等于时始终覆盖hashCode()” - Item-9: “Always override hashCode() when you override equals” 当我覆盖equals()方法时,为什么要覆盖hashCode()? - Why should I override hashCode() when I override equals() method? 如果在使用LruCache类时不覆盖sizeof会发生什么 - what happen if I don't override sizeof when using LruCache class 仅使用一个变量覆盖 HashCode() 的正确方法是什么? - What is the correct way to override HashCode() using only one variable? 如果我们只覆盖类中的hashCode()并在Set中使用它会发生什么? - What happens if we override only hashCode() in a class and use it in a Set? 当String只由数字组成时,我应该如何覆盖hashCode? - When a String consists solely of digits, how should I override hashCode? 当AsyncTasks已满时会发生什么? - What will happen when AsyncTasks are full?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM