String的equals是怎样实现的?equals方法如何重写?

2020-04-28 17:48:47 java常见问答 10455

我们平时在java开发过程中,经常可能会遇到要对字符参数做一些比较,其中比较常用的就不能不说equals方法了,那么你知道你经常用的String的equals是怎么实现的吗?怎么去重写equals方法呢?

我们先看一下Object类的equals方法的实现:

public static bool Equals(object objA, object objB)
{
    if (objA == objB) //如果两个对象的引用相同,都指向同一个对象那么肯定是相等
    {
        return true;
    }
    if ((objA != null) && (objB != null)) //如果两个对象之一为null 那么肯定不相当
    {
        return objA.Equals(objB);
    }
    return false;
}
public virtual Boolean Equals(Object obj)
{
    if (this == obj) return true; //如果两个对象的引用相同,都指向同一个对象那么肯定是相等
    return false;
}

其实在设计类型的时候我们可以分3种情况:

我们当前所设计的引用类的基类型如果说没有重写Object的Equals方法而是直接继承得来,那么实现Equals方法可以这样:

lass MyRefType: BaseType
{
    RefType refobj;
    ValType valobj;
    public override Boolean Equals(Object obj)
    {
        if (obj == null) return false; //当前对象this不可能为null,所以如果obj为null,那么肯定不相等
        if (this.GetType() != obj.GetType()) return false; //如果连类型都不同,那么肯定不相同啦
        MyRefType other = (MyRefType) obj; //因为类型已经可以肯定相同,转换安全
        if (!Object.Equals(refobj, other.refobj)) return false; //比较引用类型字段,这里只有用Object的静态方法Equals来比较,为什么?刚才看了Object的静态方法实现,其中是使用比较对象之一的实例方法Equals来比较的,而我们现在正在这个类型的实例方法Equals中,这样会不会引起循环引用?
        if (!valobj.Equals(other.valobj)) return false; //比较值类型字段
        return true; //到这里两个对象才相同
    }
    public static Boolean operator == (MyRefType o1, MyRefType o2)
    {
        return Object.Equals(o1, o2);
    }
    public static Boolean operator != (MyRefType o1, MyRefType o2)
    {
        return !(o1 == o2);
    }
}

当我们从Object类的静态Equals方法的实现可以看出实现Equals方法时,只要实现当前类型的实例方法Equals就行了,静态方法也就可以免了,直接调用Object类的静态Equals方法即可,因为最终比较还是要使用这个子类的实例方法。

如果说我们当前所设计的引用类的基类型重写了Object的Equals方法,那么实现Equals方法可以这样:

class MyRefType: BaseType
{
    RefType refobj;
    ValType valobj;
    public override Boolean Equals(Object obj)
    {
        if (!base.Equals(obj)) return false; //如果连基类型都认为对象不相等,那么就不可能相等
        if (obj == null) return false; //当前对象this不可能为null,所以如果obj为null,那么肯定不相等
        if (this.GetType() != obj.GetType()) return false; //如果连类型都不同,那么肯定不相同啦
        MyRefType other = (MyRefType) obj; //因为类型已经可以肯定相同,转换安全
        if (!Object.Equals(refobj, other.refobj)) return false; //比较引用类型字段,这里只有用Object的静态方法Equals来比较,为什么?刚才看了Object的静态方法实现,其中是使用比较对象之一的实例方法Equals来比较的,而我们现在正在这个类型的实例方法Equals中,这样会不会引起循环引用?
        if (!valobj.Equals(other.valobj)) return false; //比较值类型字段
        return true; //到这里两个对象才相同
    }
    public static Boolean operator == (MyRefType o1, MyRefType o2)
    {
        return Object.Equals(o1, o2);
    }
    public static Boolean operator != (MyRefType o1, MyRefType o2)
    {
        return !(o1 == o2);
    }
}

注意:当基类按照自己的逻辑重写Object的Equals方法时,那么必须先调用基类的Equals方法来判断,否则我们的Equals实现可能总是先判断两个对象的引用是否相同,这样可能大部分情况下都是永远返回false。

为值类型实现Equals方法:

先来看看System.ValueType的Equals方法的实现:

public override bool Equals(object obj)
{
    if (obj == null)
    {
        return false;
    }
    RuntimeType type1 = (RuntimeType) base.GetType(); //获取运行时类型
    RuntimeType type2 = (RuntimeType) obj.GetType();
    if (type2 != type1) //类型都不同,就没有机会相等
    {
        return false;
    }
    object obj1 = this;
    if (ValueType.CanCompareBits(this))
    {
        return ValueType.FastEqualsCheck(obj1, obj);
    }
    FieldInfo[] infoArray1 = type1.InternalGetFields(BindingFlags.NonPublic | (BindingFlags.Public | BindingFlags.Instance), false);
    for (int num1 = 0; num1 < infoArray1.Length; num1++) //比较每个字段的值
    {
        object obj2 = ((RuntimeFieldInfo) infoArray1[num1])
            .InternalGetValue(obj1, false);
        object obj3 = ((RuntimeFieldInfo) infoArray1[num1])
            .InternalGetValue(obj, false);
        if (obj2 == null)
        {
            if (obj3 != null)
            {
                return false;
            }
        }
        else if (!obj2.Equals(obj3))
        {
            return false;
        }
    }
    return true;
}
可以这样实现:
struct MyValType
{
    RefType refobj;
    ValType valobj;
    publci override Boolean Equals(Object obj)
    {
        if (!(obj is MyValType)) return false;
        return this.Equals((MyValType) obj);
    }
    public Boolean Equals(MyValType obj)
    {
        if (!Object.Equals(this.refobj, obj.refobj)) return false;
        if (!this.valobj.Equals(obj.valobj)) return false;
        return true;
    }
    public static Boolean operator == (MyValType v1, MyValType v2)
    {
        return v1.Equals(v2);
    }
    public static Boolean operator != (MyValType v1, MyValType v2)
    {
        return !(v1 == v2);
    }
}

好了,以上就是有关String中的equals实现的所有内容了,还想了解更多java常见问答记得来关注本站消息哦。