关于==,equals和hashCode

关于==,equals和hashCode的比较是一个经常被问到的问题,要牢记答案必须先知道其原理,下面先从他们的原理,使用和注意事项来阐述他们:

1.原理

==比较的是2个对象是否指向的同一个引用,只有指向同一个引用才返回true;

equals方法在Object类中return this == obj,默认指向同一个引用才返回true;

hashCode方法在Object类中定义返回一个int类型。

2.使用

equals:

通常一个类需要定义equals方法是为了比较该类中不同实例中全部或者部分属性值是否相等,我们只需要在自定义的equals方法中去比较我们所关心的字段就好。如果这些字段全部相等,就可以返回true,否则返回false;至于Object类中使用==来判断是出于性能考虑,毕竟比较字段更浪费性能,既然他们指向的引用是同一个,那么他们包含的字段自然也相等。下面我们看一下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;
}

1.如果指向相同引用,返回true,同Object类一样;

2.如果是不同引用,对象类型又不一致,返回false;这里要说明的是,通常使用equals方法都是在同一个类型,不同实例之间使用。如果存在继承关系的话,可以使用getClass()方法来比较他们是否属于同一个类模板。因为 子类 instanceof 父类 会返回true;

3.比较各属性值。String类型底层是一个char数组,比较每一个char的值是否相等,全部相等才返回true。


hashCode:

在我们定义equals方法后都会去自定义一个hashCode方法,提供计算散列值。之所以这样做是为了更好的支持一些基于hash算法的容器,Hashtable, HashMap, HashSet 等。

通常重写hashCode方法会将equals方法中使用到的字段全部纳入计算当中,得出一个最终的int值。

下面我们看一下String类中是如何重写hashCode方法的:

/** Cache the hash code for the string */
private int hash; // Default to 0

public int hashCode() {
    int h = hash;
    if (h == 0 && value.length > 0) {
        char val[] = value;

        for (int i = 0; i < value.length; i++) {
            h = 31 * h + val[i];
        }
        hash = h;
    }
    return h;
}

定义了一个算法 h = 31 * h + val[i] 来计算hashCode;其中每一个字符都参与该计算。之所以使用31,并不是硬性要求,而是为了避免hash碰撞产生重复值,故而使用一个质数。

3.注意事项

网上很多文章都在提equals方法和hashCode方法需要遵守一些规则,实际上这些规则是定义在Object类的方法注释中的,大家可以去读一读源码注释。很多笔试题中都会出现给定一个equals方法,让笔试者选择或者写出一个hashCode方法的实现,实际上就是考察的这些规则。下面我先列举出需要注意的规范:

关于equals方法

  • 自反性。对于任何非null的引用值x,x.equals(x)必须返回true。
  • 对称性。对于任何非null的引用值x和y,当且仅当y.equals(x)返回true时,x.equals(y)必须返回true
  • 传递性。对于任何非null的引用值x、y和z,如果x.equals(y)返回true,并且y.equals(z)也返回true,那么x.equals(z)也必须返回true。
  • 一致性。对于任何非null的引用值x和y,只要equals的比较操作在对象中所用的信息没有被修改,多次调用该x.equals(y)就会一直地返回true,或者一致地返回false。
  • 对于任何非null的引用值x,x.equals(null)必须返回false。

关于hashC方法

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

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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值