• equals和hashCode


    先谈equals。
    equals是Object类提供的方法之一,众所周知,每一个java类都继承自Object类,
    所以说每一个对象都有equals这个方法。而我们在用这个方法时却一般都重写这个方法,why?
    

    Ok,先看一个Object类中equals()方法的源代码:

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

          从这个方法中可以看出,只有当一个实例等于它本身的时候,equals()才会返回true值。通俗地说,此时比较的是两个引用是否指向内存中的同一个对象,也可以称做是否实例相等。而我们在使用equals()来比较两个指向值对象的引用的时候,往往希望知道它们逻辑上是否相等,而不是它们是否指向同一个对象——这就是我们通常重写这个方法的原因。

          在程序员之家论坛中有这样一篇文章《全面理解Java中的String数据类型》(链接http://www.phome.asia/forum/thread/19667.html) ,在这篇文章中,String s1 = new String(“kvill”),String s2 = new String(“kvill”); s1.equals(s2)为ture,说明String类中已经重写了equals()方法,如果不重写equals()方法,那么s1.equals(s2)默认比较两个对象所指向的内存地址是否相同,返回值必然为false。

           重写equals()方法看起来非常简单,但是有许多改写的方式会导致错误,并且后果非常严重。要想正确改写equals()方法,你必须要遵守它的通用约定。下面是约定的内容,来自java.lang.Object的规范,equals方法实现了等价关系,以下是要求遵循的5点,这5点都是当年数学的概念啊……,呵呵,且看:

    1. 自反性:对于任意的引用值x,x.equals(x)一定为true。 

    2. 对称性:对于任意的引用值x 和 y,当x.equals(y)返回true时,y.equals(x)也一定返回true。 

    3. 传递性:对于任意的引用值x、y和z,如果x.equals(y)返回true,并且y.equals(z)也返回true,那么x.equals(z)也一定返回true。

    4. 一致性:对于任意的引用值x 和 y,如果用于equals比较的对象信息没有被修改,多次调用x.equals(y)要么一致地返回true,要么一致地返回false。

    5. 非空性:对于任意的非空引用值x,x.equals(null)一定返回false。

          了解了equals重写,我们再看hashCode()这个方法,hashcode()这个方法也是从object类中继承过来的,在object类中定义如下: 

           public native int hashCode(); 

          说明是一个本地方法,它的实现是根据本地机器相关的。再看它比较“官方”的详细说明:hashCode()返回该对象的哈希码值,该值通常是一个由该对象的内部地址转换而来的整数,它的实现主要是为了提高哈希表(例如java.util.Hashtable提供的哈希表)的性能。

          你可以对它的这样“官方式”的定义漠视,但以下这一点你必须铭记:在每个重写了equals方法的类中,你必须也要重写hashCode方法。如果不这样做的话,就会违反Object.hashCode的通用约定,从而导致该类无法与所有基于散列值(hash)的集合类结合在一起正常运行。 

          hashCode()的返回值和equals()的关系如下:

          如果x.equals(y)返回“true”,那么x和y的hashCode()必须相等。 

          如果x.equals(y)返回“false”,那么x和y的hashCode()有可能相等,也有可能不等。

    说了这么多,他们之间的具体关系还是看个例子好,以下是51px中吴老师的一个例子。

    public class TestEquals {
    	public static void main(String args[]) {
    		Student s1 = new Student("张一", 6);
    		Student s2 = new Student("张一", 6);
    
    		if (s1.equals(s2)) {
    			System.out.println("相同  s1的代码:" + s1.hashCode() + "  s2的代码:"
    					+ s2.hashCode());
    		} else {
    			System.out.println("不相同");
    		}
    	}
    }
    
    class Student {
    	private int age;
    	private String name;
    	
    	public Student() {
    	}
    
    	public Student(String name, int age) {
    		this.age = age;
    		this.name = name;
    	}
    
    	public int getAge() {
    		return age;
    	}
    
    	public void setAge(int age) {
    		this.age = age;
    	}
    
    	public String getName() {
    		return name;
    	}
    
    	public void setName(String name) {
    		this.name = name;
    	}
    
    	public int hashCode() {
    		return (this.name.hashCode() + this.age) * 31;
    	}
    
    	public boolean equals(Object obj) {
    		boolean result = false;
    		if (obj == null) {
    			result = false;
    		}
    		if (this == obj) {
    			result = true;
    		}
    
    		if (obj instanceof Student) {
    			Student stu = (Student) obj;
    			if (stu.getName().equals(this.name) && stu.getAge() == (this.age)) {
    				result = true;
    			}
    
    		} else {
    			result = false;
    		}
    		return result;
    	}
    }
  • 相关阅读:
    Java之冒泡完整理解
    Java 之数组的复制,
    python 小白之路(跳动的球)
    小白之旅,Python运算符
    在学习枯燥的Java中遇见美丽的Jframe,窗体中的单选按钮(JRadioButton)
    自定义的无数据提示界面
    北京地铁站经纬度集合(包含大部分)
    自定义UItextFiled,限制TextFiled 的输入长度
    消息发送机制的利用
    app 后台持续定位
  • 原文地址:https://www.cnblogs.com/heartstage/p/3384696.html
Copyright © 2020-2023  润新知