equals、==、hashcode的使用

www.51xuejava.com

首先我们了解下Object中的equals和hashcode方法

equals方法指示其他某个对象是否与此对象“相等”。

equals 方法在非空对象引用上实现相等关系:

  • 自反性:对于任何非空引用值 xx.equals(x) 都应返回 true
  • 对称性:对于任何非空引用值 xy,当且仅当 y.equals(x) 返回true 时,x.equals(y) 才应返回true
  • 传递性:对于任何非空引用值 xyz,如果 x.equals(y) 返回 true,并且 y.equals(z) 返回 true,那么x.equals(z) 应返回true
  • 一致性:对于任何非空引用值 xy,多次调用 x.equals(y) 始终返回true 或始终返回false,前提是对象上 equals 比较中所用的信息没有被修改。
  • 对于任何非空引用值 xx.equals(null) 都应返回 false

Object 类的 equals 方法实现对象上差别可能性最大的相等关系;即,对于任何非空引用值 xy当且仅当xy 引用同一个对象时,此方法才返回truex == y 具有值true)。

源码:

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

hashCode方法

 

返回该对象的哈希码值。支持此方法是为了提高哈希表(例如 java.util.Hashtable 提供的哈希表)的性能。

hashCode 的常规协定是:

  • 在 Java 应用程序执行期间,在对同一对象多次调用 hashCode 方法时,必须一致地返回相同的整数,前提是将对象进行 equals 比较时所用的信息没有被修改。从某一应用程序的一次执行到同一应用程序的另一次执行,该整数无需保持一致。
  • 如果根据 equals(Object) 方法,两个对象是相等的,那么对这两个对象中的每个对象调用 hashCode 方法都必须生成相同的整数结果。
  • 如果根据 equals(java.lang.Object) 方法,两个对象不相等,那么对这两个对象中的任一对象上调用 hashCode 方法 要求一定生成不同的整数结果。但是,程序员应该意识到,为不相等的对象生成不同整数结果可以提高哈希表的性能。

实际上,由 Object 类定义的 hashCode 方法确实会针对不同的对象返回不同的整数。(这一般是通过将该对象的内部地址转换成一个整数来实现的,但是 JavaTM 编程语言不需要这种实现技巧。)

 

一般情况下,

==操作比较的是两个变量的值是否相等,对于引用型变量表示的是两个变量在堆中存储的地址是否相同,即栈中的内容是否相同。
equals
操作表示的两个变量是否是对同一个对象的引用,即堆中的内容是否相同。

 

从equals源码也可看出

    对于引用类型而言,==和equals效果一致,所以通常我们自定义的类创建的两个对象使用equals比较都是不一样的(false)【原因:对应堆中的地址不一样】。

那么这时候大家可能就想到我们常见的一个问题:String也是一个对象,那么使用String的equals比较

    String s3 = new String("123");//“123”是常量池中的一个对象,new String("123")实际上是将这个对象复制了一份放到了堆中 
            String s4 = new String("123"); 
            System.out.println("测试s3==s4:"+(s3 == s4)); //false
            System.out.println("测试s3 equals s4:"+s3.equals(s4));//string 123  true

为什么04行是true呢,这边就涉及到equals方法的重写

看String类equals源码:实际上比较的是内部的字符串序列

    public boolean equals(Object anObject) { 
        if (this == anObject) { 
            return true; 
        } 
        if (anObject instanceof String) { 
            String anotherString = (String) anObject; 
            int n = value.length; 
            if (n == anotherString.value.length) { 
                char v1[] = value; 
                char v2[] = anotherString.value; 
                int i = 0; 
                while (n-- != 0) { 
                    if (v1[i] != v2[i]) 
                            return false; 
                    i++; 
                } 
                return true; 
            } 
        } 
        return false; 
    } 


相同的情况还有一些,如:包装类、Date……

 


对于我们自定义的类,如下:

    public class RewriteEquals { 
         
        private int p; 
         
        public RewriteEquals(int p){ 
            this.p = p; 
        } 
    } 


    public static void main(String[] args) { 
            RewriteEquals re1 = new RewriteEquals(2); 
            RewriteEquals re2 = new RewriteEquals(2); 
            RewriteEquals re3 = new RewriteEquals(3); 
            System.out.println(re1.equals(re2)); 
             
        } 

明显,我们现在比较出的值是:false

重写equals方法如下

    public class RewriteEquals { 
         
        private int p; 
         
        public RewriteEquals(int p){ 
            this.p = p; 
        } 
         
        @Override 
        public boolean equals(Object obj) { 
            // TODO Auto-generated method stub 
            if (this == obj) { 
                return true; 
            } 
            if (obj instanceof RewriteEquals) { 
                if(((RewriteEquals) obj).p == this.p){ 
                    return true; 
                } 
            } 
            return false; 
        } 
    } 

此时,调用main方法,返回的是:true;

下面我们将涉及到hash相关,问题又出来了:

    public static void main(String[] args) { 
            RewriteEquals re1 = new RewriteEquals(2); 
            RewriteEquals re2 = new RewriteEquals(2); 
            RewriteEquals re3 = new RewriteEquals(3); 
            System.out.println(re1.equals(re2)); 
             
            HashMap map = new HashMap(); 
            map.put(re1, 10); 
            map.put(re3, 20); 
            System.out.println(map.get(new RewriteEquals(3))); 
             
        } 


第10行返回的是:null,为什么呢,因为对象本身的hashcode还是使用的Object类中hashCode方法获取的,内存中的地址!

这时候我们需要重写hashCode方法,以达到我们的目的,全部代码如下:

    package com.xuejava51.teach.high.equals; 
     
    import java.util.HashMap; 
     
    public class RewriteEquals { 
         
        private int p; 
         
        public RewriteEquals(int p){ 
            this.p = p; 
        } 
         
        @Override 
        public boolean equals(Object obj) { 
            // TODO Auto-generated method stub 
            if (this == obj) { 
                return true; 
            } 
            if (obj instanceof RewriteEquals) { 
                if(((RewriteEquals) obj).hashCode() == this.hashCode()){ 
                    return true; 
                } 
            } 
            return false; 
        } 
         
        @Override 
        public int hashCode() { 
            // TODO Auto-generated method stub 
            return this.p*10; 
        } 
         
        public static void main(String[] args) { 
            RewriteEquals re1 = new RewriteEquals(2); 
            RewriteEquals re2 = new RewriteEquals(2); 
            RewriteEquals re3 = new RewriteEquals(3); 
            System.out.println(re1.equals(re2)); 
             
            HashMap map = new HashMap(); 
            map.put(re1, 10); 
            map.put(re3, 20); 
            System.out.println(map.get(new RewriteEquals(3))); 
             
        } 
         
    } 


视频请观看:地址

equals、==、hashcode的使用

上一篇:SRM 555


下一篇:LA 3644 X-Plosives / 并查集