zoukankan      html  css  js  c++  java
  • 讲解:为什么重写equals时必须重写hashCode方法

    一 :string类型的==和equals的区别:

            结论:"=="是判断两个字符串的内存地址是否相等,equals是比较两个字符串的值是否相等,具体就不做扩展了,有兴趣的同学可以去查看相关的博客。

            String s1 = new String("java");

           String s2 = new String("java");

           System.out.println(s1==s2); //false

           System.out.println(s1.equals(s2)); //true

           在Java中,equals和hashCode方法是Object中提供的两个方法,string类型重写了equals()方法和hashCod()方法,源码如下:

    public boolean equals(Object anObject) {
    	    if (this == anObject) {
    	        return true;
    	    }
    	    if (anObject instanceof String) {
    	        String anotherString = (String)anObject;
    	        int n = count;
    	        if (n == anotherString.count) {
    	        char v1[] = value;
    	        char v2[] = anotherString.value;
    	        int i = offset;
    	        int j = anotherString.offset;
    	        while (n-- != 0) {
    	            if (v1[i++] != v2[j++])
    	            return false;
    	        }
    	        return true;
    	        }
    	    }
    	    return false;
    	    }
    
    	/*返回哈希码,String的哈希码计算方式为s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]*/
    	public int hashCode() {
    	    int h = hash;
    	    if (h == 0) {
    	        int off = offset;
    	        char val[] = value;
    	        int len = count;
    
                for (int i = 0; i < len; i++) {
                    h = 31*h + val[off++];
                }
    	            hash = h;
            }
    	        return h;
        }
    

      

     二:对象equals 和hashcode的关系

    结论:当对象的equals()方法被重写时,通常有必要重写 hashCode() 方法,以维护 hashCode 方法的常规协定,该协定声明相等对象必须具有相等的哈希码。如下:

              (1)两个对象相等,hashcode一定相等

              (2)两个对象不等,hashcode不一定不等

              (3)hashcode相等,两个对象不一定相等

              (4)hashcode不等,两个对象一定不等

              hashcode是用于散列数据的快速存取,如利用HashSet/HashMap/Hashtable类来存储数据时,都是根据存储对象的hashcode值来进行判断是否相同的。这样如果我们对一个对象重写了euqals,意思是只要对象的成员变量值都相等那么euqals就等于true,但 不重写hashcode,那么我们再new一个新的对象,当原对象.equals(新对象)等于true时,两者的hashcode却是不一样的,由此将产生了理解的不一致。

    三 :使用HashMap,如果key是自定义的类,就必须重写hashcode()和equals()

        A.当put元素时:
                  1.首先根据put元素的key获取hashcode,然后根据hashcode算出数组的下标位置,如果下标位置没有元素,直接放入元素即可。
                  2.如果该下标位置有元素(即根据put元素的key算出的hashcode一样即重复了),则需要已有元素和put元素的key对象比较equals方法,如果equals不一样,则说明可以放入进map中。这里由于hashcode一样,所以得出的数组下标位置相同。所以会在该  数组位置创建一个链表,后put进入的元素到放链表头,原来的元素向后移动。       
            B.当get元素时:
                 根据元素的key获取hashcode,然后根据hashcode获取数组下标位置,如果只有一个元素则直接取出。如果该位置一个链表,则需要调用equals方法遍历链表中的所有元素与当前的元素比较,得到真正想要的对象。
            

           C. 采用hashcode的好处:

              如果我们不使用hashcode,直接使用equals比较,那么我们有10w个元素,put值或者get值时要比较10w次,如果先通过hashcode判断后,我们的效率就会提高很多。

              我们可以对比实际生活中,如果有一栋教学楼,一楼是1年级,二楼是2年级,以此类推,六楼是6年级,这时我们需要找5年级2班在哪间教室,通过hashcode直接定位到5楼,然后在5楼一间间找就行了,这样避免从一楼一间一间查看。

           

     四.:代码展示,为什么重写equals时必须重写hashCode方法

             我们以一个student 学生类来测试重写equals()和重写hashcode()后,map的get()方法返回值结果,让大家清晰了解为什么重写equals时必须重写hashCode方法

              

    package com.sinaif;
    
    public class Student {
    	private String name; //姓名
    	private String sex;  //性别
    	private String idCard;//身份证号
    	Student(String name,String sex,String idCard){
    		this.name = name;
    		this.sex = sex;
    		this.idCard = idCard;
    	}
    	
    	public String getName() {
    		return name;
    	}
    	public void setName(String name) {
    		this.name = name;
    	}
    	public String getSex() {
    		return sex;
    	}
    	public void setSex(String sex) {
    		this.sex = sex;
    	}
    	public String getIdCard() {
    		return idCard;
    	}
    	public void setIdCard(String idCard) {
    		this.idCard = idCard;
    	}
    	
    	@Override
    	public boolean equals(Object obj) {
    		// TODO Auto-generated method stub
    		if(obj == null){
    			return false;
    		}
    		Student obj1 = (Student)obj;
    		if(this.name.equals(obj1.getName()) && this.idCard.equals(obj1.getIdCard())){
    			return true;
    		}
    		return false;
    	}
    	
    	//@Override
    	public int hashCode() {
    		// TODO Auto-generated method stub
    		String s= this.name + this.idCard;
    		return s.hashCode();
    	}
    	
    }
    

     

    public static void main(String[] args) throws Exception {
    		Map<Student,Student> map = new HashMap<Student,Student>();
    		Student s1 = new Student("haly","male","110200");
    		Student s2 = new Student("haly","female","110200");
    		map.put(s1, s1);
      
    		System.out.println(map.get(s2)); 
    		
    		// 当没有重写equals方法和hashcode方法,打印出null
    		// 当重写equals方法,不重写hashcode方法时,打印出null
    		// 当重写equals方法,并且重写hashcode方法时,打印出com.test.Student@95fb7d6
    		
    	} 
    

      

      

  • 相关阅读:
    POJ 2342
    SHU 413
    SHU 414
    进制转换模板
    SHU 第15届上海大学程序设计联赛夏季赛[热身赛] 第三题(G题)
    POJ 3185
    XTU 1260
    高斯消元法模板
    POJ 2057
    模态窗口的定时关闭
  • 原文地址:https://www.cnblogs.com/haly/p/10718106.html
Copyright © 2011-2022 走看看