Java ==和equals详解,以及重写equals() 和 hashCode() [ 源码实例 ]

发布时间:2018-08-03作者:laosun阅读(1992)

Java

Java 重写equals() 和 hashCode()

    java的==和equals的对比方式。

    1、基本数据类型比较

    ==和Equals都比较两个值是否相等。相等为true 否则为false;

    2、引用对象比较

    ==和Equals都是比较栈内存中的地址是否相等 。相等为true 否则为false;

    下边来看个例子:

    package com.sunjs.java;
    
    public class EqualsTest {
    
    	public static void main(String[] args) {
    		System.out.println("================基本数据类型比较===============");
    		//在str1指向常量池中的abc,str2也指向了常量池中的abc 
    		String str1 = "abc";
    		String str2 = "abc";
    		System.out.println("基本数据类型==比较:"+ (str1==str2));
    		System.out.println("基本数据类型equals比较:"+ (str1.equals(str2)));
    
    		
    		System.out.println("\n================引用对象比较 1===============");
    		
    		//new 了两次,相当于在堆内存中创建了两个不同的对象,所以a和b两个引用分别指向了两个对象
    		Integer a = new Integer(1);
    		Integer b = new Integer(1);
    		System.out.println("Integer引用对象==比较:"+ (a == b));
    		//a和b指向了两个对象,为什么equals对比还是一样的呢,具体请查看Integer类的equals方法和hashcode方法就清楚原因了
    		System.out.println("Integer引用对象equals比较:"+ (a.equals(b)));
    
    		System.out.println("\n================引用对象比较 2===============");
    		
    		Users userA = new Users("sun", 18);
    		Users userB = new Users("sun", 18);
    		
    		//从这里打印hashcode可以得出,两个引用指向了两个不同的堆对象,所以hashcode也不一样
    		//这里呢,我们需要知道一点,equals()相同时 hashcode 必须相同, 但是hashcode相同并不一定eqauls相同
    		//具体为什么呢,自己去百度、google一下。
    		System.out.println(userA.hashCode()+"  ==  "+userB.hashCode());
    		
    		//因为userA和userB是两个不同的引用,也指向了两个不同的堆对象,所以他们==必然是不同的
    		System.out.println("引用对象==比较:"+ (userA == userB));
    
    		//同上,引用不同,对比自然不同
    		System.out.println("引用对象equals比较:"+ (userA.equals(userB)));
    	}
    
    }
    class Users {
    	private String name;
    	private int age;
    
    	public Users() {
    		super();
    	}
    
    	public Users(String name, int age) {
    		super();
    		this.name = name;
    		this.age = age;
    	}
    
    	public String getName() {
    		return name;
    	}
    
    	public void setName(String name) {
    		this.name = name;
    	}
    	
    	public int getAge() {
    		return age;
    	}
    
    	public void setAge(int age) {
    		this.age = age;
    	}
    	
    }

    打印结果:

    ================基本数据类型比较===============
    基本数据类型==比较:true
    基本数据类型equals比较:true
    
    ================引用对象比较 1===============
    Integer引用对象==比较:false
    Integer引用对象equals比较:true
    
    ================引用对象比较 2===============
    204349222  ==  231685785
    引用对象==比较:false
    引用对象equals比较:false

    下边来演示一下重写equals方法和hashcode方法的三种方式:

    1:我们使用17和31散列码,这种想法来自于一本经典的java书籍《Effective Java》。这本书已经出到第三版了,不过是英文的,中文的只有第二版可以看。 还有一本书比较经典,也推荐大家看看,博主现在正在细看《Java编程思想》,也就是Thinking in Java,这本书第四版已经出来好几年了。

    package com.sunjs.java;
    
    public class EqualsTest {
    
    	public static void main(String[] args) {
    		System.out.println("================引用对象比较(重写equals和hashcode方法 1 )================");
    		//创建Mac对象,并且重写equals和hashcode方法
    		//虽然从理论上来说重写equals方法就能达到我们想要的结果,但是这样不利于哈希表的性能,也不符合hashcode的规则
    		Mac mac1 = new Mac("13寸", 14500.00, 11);
    		Mac mac2 = new Mac("13寸", 14500.00, 11);
    		System.out.println(mac1.hashCode()+"  ==  "+mac2.hashCode());
    		System.out.println("重写-引用对象==比较:"+ (mac1 == mac2));
    		//很明显重新后equals比较是样的。
    		System.out.println("重写-引用对象equals比较:"+ (mac1.equals(mac2)));
    		
    	}
    
    }
    class Mac{
    	private String name;
    	private Double money;
    	private Integer num;
    
    	public Mac() {
    		super();
    	}
    
    	public Mac(String name, Double money, Integer num) {
    		super();
    		this.name = name;
    		this.money = money;
    		this.num = num;
    	}
    
    	public String getName() {
    		return name;
    	}
    
    	public void setName(String name) {
    		this.name = name;
    	}
    
    	public Double getMoney() {
    		return money;
    	}
    
    	public void setMoney(Double money) {
    		this.money = money;
    	}
    	
    	public Integer getNum() {
    		return num;
    	}
    
    	public void setNum(Integer num) {
    		this.num = num;
    	}
    
    	//重写equals方法
    	@Override
    	public boolean equals(Object obj) {
    		if(obj==this){
    			return true;
    		}
    		if(!(obj instanceof Mac)){
    			return false;
    		}
    		Mac mac = (Mac)obj;
    		return mac.getName().equals(name) && mac.getMoney().equals(money) && mac.getNum()==num;
    	}
    	/**
    	 * 重写hashcode方法
    	 * 这种17和31散列码的想法来自经典的Java书籍——《Effective Java》第九条
    	 * @author sun
    	 * @return
    	 */
    	@Override
    	public int hashCode() {
    		int result = 17;
    		result = 31 * result + name.hashCode();
    		result = 31 * result + money.hashCode();
    		result = 31 * result + num;
    		return result;
    	}
    
    }

    打印结果:

    ================引用对象比较(重写equals和hashcode方法 1 )================
    -588737296  ==  -588737296
    重写-引用对象==比较:false
    重写-引用对象equals比较:true


    2:对于JDK7及更新版本,你可以是使用java.util.Objects 来重写 equals 和 hashCode 方法,代码如下

    这里我就只贴重要的代码(equals和hashcode):

    @Override
    	public boolean equals(Object obj) {
    		if(obj==this){
    			return true;
    		}
    		if(!(obj instanceof Mac)){
    			return false;
    		}
    		Mac mac = (Mac)obj;
    		return Objects.equals(mac.getName(), name) && Objects.equals(mac.getMoney(), money) && mac.getNum()==num;
    	}
    	@Override
    	public int hashCode() {
    		return Objects.hash(name, money, num);
    	}


    3:使用Apache Commons Lang 包中的 EqualsBuilder 和HashCodeBuilder 方法

    使用此方法导jar包

    @Override
    	public boolean equals(Object obj) {
    		if(obj==this){
    			return true;
    		}
    		if(!(obj instanceof Mac)){
    			return false;
    		}
    		Mac mac = (Mac)obj;
    		return new EqualsBuilder().append(mac.getName(), name).append(mac.getMoney(), money).append(mac.getNum(), num).isEquals();
    	}
    	@Override
    	public int hashCode() {
    		return new HashCodeBuilder(17, 37).append(name).append(money).append(num).toHashCode();
    	}

    其实后两种都是对于17和31散列码思想的封装实现!

0 +1

版权声明

 Java  源码

 请文明留言

0 条评论