听说,你也一直钟爱着equals。。。

脑补一下final

final 用于声明变量/参数/属性、方法和类。

  • 修饰变量:如果变量是基本类型,其值不变;如果是对象,则引用不可再变(内容可变)。
  • 修饰方法:方法不可重写(是否可继承取决于方法的访问修饰符)
  • 修饰类:类不可被继承。

 



 

==与equals的区别

我想,大家常规的解释是:==是操作符,比较基本类型,则为其值;比较引用类型,则用以比较两个对象在内存中的哈希地址。 equals是方法,比较的是变量的内容。

---------------

equals是超类Object的方法。参数是一个object对象。本文我将重点借助JAVADOC和源码来阐释。

 


java.lang.Object里对equals方法的说明:

/**

Indicates whether some other object is "equal to" this one.
The equals method implements an equivalence relation on non-null object references:
  • It is reflexive: for any non-null reference value x, x.equals(x) should return true.
  • It is symmetric: for any non-null reference values x and y, x.equals(y) should return true if and only if y.equals(x) returns true.
  • It is transitive: for any non-null reference values x, y, and z, if x.equals(y) returns true and y.equals(z) returns true, then x.equals(z) should return true.
  • It is consistent: for any non-null reference values x and y, multiple invocations of x.equals(y) consistently return true or consistently return false, provided no information used in equals comparisons on the objects is modified.
  • For any non-null reference value x, x.equals(null) should return false.
The equals method for class Object implements the most discriminating possible equivalence relation on objects; that is, for any non-null reference values x and y, this method returns true if and only if x and y refer to the same object (x == y has the value true).
Note that it is generally necessary to override the hashCode method whenever this method is overridden, so as to maintain the general contract for the hashCode method, which states that equal objects must have equal hash codes.
Parameters:
obj - the reference object with which to compare.
Returns:
true if this object is the same as the obj argument; false otherwise.
See Also:
hashCode(), java.util.HashMap
*/
public boolean equals(Object obj) {
    return (this == obj);
}

可见equals默认是比较对象的哈希值。

String、Integer这些包装类重写了equals方法。重写的逻辑都是先判断类型是否匹配,然后String是看字符串里每个char字符是否都相同,Integer是两个Integer实例的intValue。

//java.lang.String

/**
     * Compares this string to the specified object.  The result is {@code
     * true} if and only if the argument is not {@code null} and is a {@code
     * String} object that represents the same sequence of characters as this
     * object.
*/
    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;
}



//java.lang.Integer

/**
     * Compares this object to the specified object.  The result is
     * {@code true} if and only if the argument is not
     * {@code null} and is an {@code Integer} object that
     * contains the same {@code int} value as this object.
*/
public boolean equals(Object obj) {
        if (obj instanceof Integer) {
            return value == ((Integer)obj).intValue();
        }
        return false;
}
java.lang.String和java.lang.Integer对equals(Object)方法的定义

 

BTW,心细的同学可以注意一下java.lang.String中另一个方法equalsIgnoreCase(String anotherString),参数类型不是Object而是String。这一点足见java之美

对于String来说,String s1="abc";String s2="abc"; System.out.println(s1==s2); 输出的结果是true。我们都知道String类是不可变的字符序列,存储在常量池中,所以当你声明了一个s1=“abc"时,就会在常量池中开辟一个内存空间来存放"abc”,下次再声明时,就会在常量池中去找,有,就直接把当前地址赋给变量,没有,就再创建。而当new String("abc")时,会开辟新的内存空间,用==比较就会返回false。

 

在做诸如String、Integer包装类型比较时,有的人一律用equals,这样会规避用==带来的比较错误的问题。这没错!不过使用equals也会带来一些隐性的bug,罪魁祸首就是它的参数类型是Object,当equals的两个对象类型不匹配时,编译器是识别不出来的。尤其当我们重构代码时,举个栗子,看下面的语句,要求在bean.platformCode是String时才有可比性。如果我们在重构或升级时将bean.platformCode属性的类型由String改为int,从String.equals方法来看,因为类型不匹配,会始终返回false,那就出bug了。所以,在做比较时,用equals取代==,会规避掉某些坑,同时呢,也会带来隐性的雷,大家在开发过程中需权衡利弊。

if("6".equals(bean.getPlatformCode())

 因此,个人认为。。。(此处见解见文末)

 



 

比较枚举类型能用==吗?

今天在codereview时,有同学发现如下用==来比较枚举,马上反问这么写没有bug么?是否测试过了?

if (ThirdPayPlatformEnums.TFB == _requestDTO.getThird_pay_platform()) {
_requestDTO.setOrder_no(_requestDTO.getOrder_no().replaceAll("[a-zA-Z]", ""));
}

他建议改用equals。

于是,大家都开始思考枚举是不是基本类型,并了解枚举是否可以用==来比较。

经查,答案是肯定的。

java.lang.Enum类对equals的定义是这样的:

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

单看这个方法实现,可能认为比较的是哈希地址。

让我们来看看这个equals方法的注解,关注一些关键词:

/**
* Returns true if the specified object is equal to this
* enum constant.
*
* @param other the object to be compared for equality with this object.
* @return true if the specified object is equal to this
* enum constant.
*/

注意到了吧,它将枚举项称为枚举常量。

进一步了解到:在官方文档中也有明确的说明

 JLS 8.9 Enums 一个枚举类型除了定义的那些枚举常量外没有其他实例了。 试图明确地说明一种枚举类型是会导致编译期异常。在枚举中final clone方法确保枚举常量从不会被克隆,而且序列化机制会确保从不会因为反序列化而创造复制的实例。枚举类型的反射实例化也是被禁止的。总之,以上内容确保了除了定义的枚举常量之外,没有枚举类型实例。

 因为每个枚举常量只有一个实例,所以如果在比较两个参考值,至少有一个涉及到枚举常量时,允许使用“==”代替equals()。

顺便贴出来java.lang.Enum里的clone方法,它保证了枚举的“单例”状态:

/**
* Throws CloneNotSupportedException. This guarantees that enums are never cloned, which is necessary to preserve their "singleton" status.
*
* @return (never returns)
*/
protected final Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException();
}

csdn《 比较java枚举成员使用equal还是==》文中分析了分别用==和equals来比较枚举的场景。最终建议是最好用==,也是考虑到了上文中提到的equals的弊端。 同样,如果是数值比较,也最好用基本类型,因为用==来比较数值无争议。



原文地址:https://www.cnblogs.com/buguge/p/8361329.html