【Effective Java 1】覆盖equals的约定

 

Object类提供equals方法,所有的类都继承Object类,也继承它的equals方法,判断类的实例是否与另一个实例相等

 

覆盖equals的步骤

1. 使用==操作符检查参数是否为这个对象的引用,如果是,则直接返回true;

2. 使用instanceof检查参数是否为正确的类型,如果不是,则直接返回false;

3. 经过第二步检查后,确定参数的类型,将参数转换为正确的类型(记住equals的参数是Object类型,在这一步就可以对参数进行类型转换了);

4. 对对象的每一个关键域,检查参数中对应域是否匹配。

 

覆盖equals的类必须覆盖hashCode方法,hashCode约定,相等的对象必须具有相等的散列码(hash code)

hashCode约定,(1)如果两个对象x和y满足x.equals(y) == true,它们的散列码应当相同。(2)如果两个对象的hashCode相同,它们并不一定相同。违背了上述原则对于使用哈希存储的系统,如果哈希码频繁的冲突将会造成存取性能急剧下降。

 

以java.lang.String为例,看一下源码

    public boolean equals(Object anObject) {
        //1. 首先使用==检查是否为同一对象
        if (this == anObject) {
            return true;
        }
        //2. 检查参数类型
        if (anObject instanceof String) {
            //3. 类型转换
            String aString = (String)anObject;
            //4. 对对象关键域匹配检查
            if (coder() == aString.coder()) {  //判断编码格式是否相同
                return isLatin1() ? StringLatin1.equals(value, aString.value)  //
                                  : StringUTF16.equals(value, aString.value);
            }
        }
        return false;
    }
    // StringLatin1的equals方法
    @HotSpotIntrinsicCandidate
    public static boolean equals(byte[] value, byte[] other) {
        if (value.length == other.length) {
            for (int i = 0; i < value.length; i++) {
                // 遍历每个字符
                if (value[i] != other[i]) {
                    return false;
                }
            }
            return true;
        }
        return false;
    }



    // StringUTF16的equals方法
    @HotSpotIntrinsicCandidate
    public static boolean equals(byte[] value, byte[] other) {
        if (value.length == other.length) {
            // 使用utf-16编码下,一个字符用2个byte来表示,所以除2才是字符个数。
            int len = value.length >> 1;
            // 遍历每个字符
            for (int i = 0; i < len; i++) {
                if (getChar(value, i) != getChar(other, i)) {
                    return false;
                }
            }
            return true;
        }
        return false;
    }

重写了equals方法之后,重写hashcode()方法,保证相同的String对象有相同的hash值

    public int hashCode() {
        //hash默认为0
        int h = hash;
        if (h == 0 && value.length > 0) {
            //返回特定编码的hash值,有值域value决定,因此可以保证equals的String对象hash相等
            hash = h = isLatin1() ? StringLatin1.hashCode(value)
                                  : StringUTF16.hashCode(value);
        }
        return h;
    }
    //StringLatin1的hashCode方法
    public static int hashCode(byte[] value) {
        int h = 0;
        for (byte v : value) {
            h = 31 * h + (v & 0xff);
        }
        return h;
    }


   //StringUTF16的hashCode方法
   public static int hashCode(byte[] value) {
        int h = 0;
        int length = value.length >> 1;
        for (int i = 0; i < length; i++) {
            h = 31 * h + getChar(value, i);
        }
        return h;
    }

 

无论何时,equals方法保证以下等价关系

1. 自反性: 对于任何非null的实例x,保证x.equals(x)返回true;

2. 对称性: 对于任何非null的实例x,y,如果x.equals(y)为true,那么y.equals(x)也为true;

3. 传递性: 对于任何非null的实例x,y,z, 如果x.equals(y)为true,y.equals(z)为true,那么x.equals(z)为true;

4. 一致性: 对于任何非null的实例x,y,只要不修改x或y, 那么x.equals(y)一直为true或者一直为false.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值