因為每個枚舉常量只有一個實例,所以如果在比較兩個參考值,至少有一個涉及到枚舉常量時,允許使用“==”代替equals() ...
腦補一下final
final 用於聲明變數/參數/屬性、方法和類。
- 修飾變數:如果變數是基本類型,其值不變;如果是對象,則引用不可再變(內容可變)。
- 修飾方法:方法不可重寫(是否可繼承取決於方法的訪問修飾符)
- 修飾類:類不可被繼承。
==與equals的區別
我想,大家常規的解釋是:==是操作符,比較基本類型,則為其值;比較引用類型,則用以比較兩個對象在記憶體中的哈希地址。 equals是方法,比較的是變數的內容。
---------------
equals是超類Object的方法。參數是一個object對象。
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.Integer
/**
* 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。這一點可見java之美。
在做諸如String、Integer包裝類型比較時,有的人一律用equals,這樣會規避用==帶來的比較錯誤的問題。這沒錯!不過使用equals也會帶來一些隱性的bug,罪魁禍首就是它的參數類型是Object,當equals的兩個對象類型不匹配時,編譯器是識別不出來的。尤其當我們重構代碼時,舉個慄子,看下麵的語句,如果我將bean的platformCode屬性的類型由String改為int,而稍有不慎忘記改下麵的語句,那就出bug了。
if("6".equals(bean.getPlatformCode())
因此,個人認為。。。(此處見解見文末)
比較枚舉類型能用==嗎?
今天有同學在review代碼時,發現如下用==來比較枚舉,馬上反問這麼寫沒有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;
}
單看這個方法實現,可能認為比較的是哈希地址。
讓我們關註一下一些關鍵詞,看這個方法的註解:
/**
* 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的弊端。 同樣,如果是數值比較,也最好用基本類型,因為用==來比較數值無爭議。