zoukankan      html  css  js  c++  java
  • hashCode与equals详解

    在工作中写业务类通常都会重写hashCode与equals方法,而这两个方法的区别与用途也常常被问道。平时也只是大概知道这二者的用途,今天闲下来,查阅资料加上自己的理

    解,总结记录下。

    hashCode()与equals()方法都是从Object类中继承过来的

     public native int hashCode();

     public boolean equals(Object obj) {
            return (this == obj);
        }

    其中hashCode 是java一个本地调用,实际上根据对象的地址来计算hashCode,而equals方法也是比较两个对象的地址值是否相同。一般而言,大部分类都自己重写实现了这

    两个方法,equals一般用来比较两个对象的内容是否相同,而hashCode则用来比较对象的hash值是否相同。

    1. 为什么要重写equals

    在大部分情形中,如果一个对象的所有属性都是相同的,则认为这两个对象是相同的,但是Object中的equals方法比较的是对象地址值是否相同,这样就导致了new的两个对

    象,虽然所有属性值都相同,但equals确实false,不符合业务。

    <span style="white-space:pre">	</span>public class Student{
    		
    		private String name;
    		
    		private String sex;
    
    		public Student(String name, String sex) {
    			super();
    			this.name = name;
    			this.sex = sex;
    		}
    	}
    	
    	@Test
    	public void test2(){
    		Student s1 = new Student("zhagnsan", "n");
    		Student s2 = new Student("zhagnsan", "n");
    		System.out.println(s1.equals(s2));
    	}
    如上例,由于Student类没有重写equals方法,则导致在测试中s1.equals(s2)返回的是false,只要重写equals方法即可,重写后的equals方法比较的对象的属性值是否相同。

    public class Student{
    	
    	private String name;
    	
    	private String sex;
    
    	public Student(String name, String sex) {
    		super();
    		this.name = name;
    		this.sex = sex;
    	}
    
    	@Override
    	public boolean equals(Object obj) {
    		if (this == obj)
    			return true;
    		if (obj == null)
    			return false;
    		if (getClass() != obj.getClass())
    			return false;
    		Student other = (Student) obj;
    		if (name == null) {
    			if (other.name != null)
    				return false;
    		} else if (!name.equals(other.name))
    			return false;
    		if (sex == null) {
    			if (other.sex != null)
    				return false;
    		} else if (!sex.equals(other.sex))
    			return false;
    		return true;
    	}
    }
    
    2. 为什么要重写hashCode

    对象的hashCode的重写一般是用在HashMap,hashSet, hashTable等集合中,这些结构中是根据对象的hash值来确定对象的存储位置。如HashMap中的Key,hashMap中

    不允许放入重复的键值,如果不重写key的hashCode,则会导致虽然两个key的值是一样的,但是是分别new出来的,内存地址是不一样的,这样hashCode()根据内存地址计

    算出来的hash值也不一样,就能在hashMap中 存入键值相同的对象,违背了hashMap的设计规则。

    还是以Student对象为例:

    @Test
    	public void test3(){
    		Student s1 = new Student("zhagnsan", "n");
    		Student s2 = new Student("zhagnsan", "n");
    		System.out.println(s1.hashCode());
    		System.out.println(System.identityHashCode(s1));
    		System.out.println(s2.hashCode());
    		System.out.println(System.identityHashCode(s2));
    	}

    输出的结果值为:

    31170373
    31170373
    28678425
    28678425
    
    其中System.identityHashCode()方法返回的是根据对象的内存地址计算出来的hash值,可以看到如果没有重写hashCode方法,直接用Object对象的hashCode方法,与直接

    用System.identityHashCode()计算出来的hash值是相同的。

    接下来在Student对象中重写hashCode方法:

    public class Student{
    	
    	private String name;
    	
    	private String sex;
    
    	public Student(String name, String sex) {
    		super();
    		this.name = name;
    		this.sex = sex;
    	}
    
    	@Override
    	public int hashCode() {
    		final int prime = 31;
    		int result = 1;
    		result = prime * result + ((name == null) ? 0 : name.hashCode());
    		result = prime * result + ((sex == null) ? 0 : sex.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;
    		Student other = (Student) obj;
    		if (name == null) {
    			if (other.name != null)
    				return false;
    		} else if (!name.equals(other.name))
    			return false;
    		if (sex == null) {
    			if (other.sex != null)
    				return false;
    		} else if (!sex.equals(other.sex))
    			return false;
    		return true;
    	}

    重新跑一遍测试,结果如下:

    -1655006615
    28678425
    -1655006615
    22440556
    可以看到,虽然两个Student对象都是new出来的,但是调用对象的hashCode返回的hash值是相同的。

    JDK规定,equals相等的两个对象hashCode值肯定相等,反之不一定。即hashCode值相等的两个对象,equals值可能相等,也可能不等。

    记得在项目中有次出现多线程访问hashMap出现死循环的问题,然后查看了下其中hashMap的部分源码。发现hashMap存储结果是数组+链表来实现的。数组的位置为key的

    hashCode的值,如果在该hash值的位置上已经有对象了,则遍历在这个位置上的链表,与链表的对象进行equals比较,如果存在相等的,在该对象已存在,如果不存在,在

    在链表的末尾加上该对象。这里就表现成hashCode值相同的对象equals不一定相等。

    equals一般用来比较对象的值(内容)是否相同,hashCode在常用在HashSet,HashMap,HashTable等结构中发挥在巨大作用。



  • 相关阅读:
    用OKR让你的员工嗨起来
    用数据让我们的OKR变得“冷酷”却更有价值
    好的想法只是OKR的开始创业者谨记
    “OKR播种机”JOHN DOERR–目标是对抗纷乱思绪的一针疫苗
    用OKR提升员工的执行力
    OKR的两个基本原则
    《OKR工作法》| 一次说太多等于什么都没说
    《OKR工作法》–让所有人承担自己的职责
    《OKR工作法》——打造一支专一的团队
    Oracle wm_concat()函数的实际运用
  • 原文地址:https://www.cnblogs.com/marcotan/p/4256904.html
Copyright © 2011-2022 走看看