enum用途 - java enum給值




比較Java枚舉成員:==或equals()? (10)

==可以用於enum

是的:枚舉具有嚴格的實例控件,允許您使用==來比較實例。 這是語言規範提供的保證(我強調):

JLS 8.9枚舉

一個枚舉類型除了由枚舉常量定義的枚舉類型之外沒有其他實例。

嘗試顯式實例化枚舉類型是編譯時錯誤。 Enumfinal clone方法確保enum常量永遠不會被克隆,並且序列化機制的特殊處理確保重複實例永遠不會由於反序列化而被創建。 禁止枚舉類型的反射實例化。 總而言之,這四件事確保enum類型的實例不會超出enum常量定義的實例。

因為每個enum只有一個實例是常量, 所以當比較兩個對象引用時,如果知道至少其中一個引用了enum常量, 則允許使用==運算符代替equals方法 。 ( Enumequals方法是一個final方法,它只是在其參數上調用super.equals並返回結果,從而執行標識比較。)

這種保證足夠強大,以至於Josh Bloch建議,如果你堅持使用單例模式,實現它的最好方法是使用單元素enum (請參閱: Effective Java第2版,第3項:強制使用單例屬性一個私有構造函數或一個枚舉類型 ;也是Singleton中的線程安全

==equals什麼區別?

作為提醒,需要說的是, ==通常不是equals的可行替代方案。 但是,如果是這樣(比如enum ),則需要考慮兩個重要區別:

==從不拋出NullPointerException

enum Color { BLACK, WHITE };

Color nothing = null;
if (nothing == Color.BLACK);      // runs fine
if (nothing.equals(Color.BLACK)); // throws NullPointerException

==在編譯時需要進行類型兼容性檢查

enum Color { BLACK, WHITE };
enum Chiral { LEFT, RIGHT };

if (Color.BLACK.equals(Chiral.LEFT)); // compiles fine
if (Color.BLACK == Chiral.LEFT);      // DOESN'T COMPILE!!! Incompatible types!

應該在適用時使用==

Bloch特別提到,具有對其實例的適當控制的不可變類可以保證其客戶端==可用。 enum被具體提及來舉例說明。

第1項:考慮靜態工廠方法而不是構造函數

[...]它允許一個不可變類保證不存在兩個相等的實例: a.equals(b)當且僅當a==b 。 如果一個類做出這種保證,那麼它的客戶可以使用==運算符而不是equals(Object)方法,這可能會提高性能。 枚舉類型提供了這種保證。

總而言之,在enum上使用==的參數是:

  • 有用。
  • 速度更快。
  • 運行時更安全。
  • 編譯時更安全。

我知道Java枚舉被編譯為具有私有構造函數和一些公共靜態成員的類。 比較給定枚舉的兩個成員時,我總是使用.equals() ,例如

public useEnums(SomeEnum a)
{
    if(a.equals(SomeEnum.SOME_ENUM_VALUE))
    {
        ...
    }
    ...
}

但是,我剛剛遇到了一些使用equals運算符==而不是.equals()的代碼:

public useEnums2(SomeEnum a)
{
    if(a == SomeEnum.SOME_ENUM_VALUE)
    {
        ...
    }
    ...
}

我應該使用哪一個操作符?


中間的枚舉是一組不變整數。 “==”就像您比較兩個整數一樣有效和正確。


使用除==以外的任何東西來比較枚舉常量是無稽之談。 這就像比較class對象與equals - 不要這樣做!

但是,Sun JDK 6u10及更早版本中存在一個令人討厭的bug( 6277781 ),可能因歷史原因而感興趣。 這個錯誤阻止了在反序列化的枚舉上正確使用== ,儘管這可以說是某種角落的情況。


兩者在技術上都是正確的。 如果您查看.equals()的源代碼,它只是按照==

然而,我使用== ,因為那將是無效的。


在枚舉的情況下都是正確的,正確的!


您可以使用: ==,equals()或switch()塊來比較枚舉,所有這些都是技術上真實的,並且可以滿足您的需要。

查看本教程以了解有關Enum常見操作的更多信息: 如何在Java中使用Enums


我想補充polygenelubricants答案:

我個人更喜歡equals()。 但它湖型的兼容性檢查。 我認為這是一個重要的限制。

要在編譯時進行類型兼容性檢查,請在枚舉中聲明並使用自定義函數。

public boolean isEquals(enumVariable) // compare constant from left
public static boolean areEqual(enumVariable, enumVariable2) // compare two variable

有了這個,你就可以獲得這兩種解決方案的所有優點:NPE保護,在編譯時易於閱讀代碼和類型兼容性檢查。

我也建議為枚舉添加一個UNDEFINED值。


我更喜歡使用==而不是equals

其他原因,除了這裡已經討論過的其他原因之外,你可以在沒有意識到的情況下引入錯誤。 假設你有這個枚舉完全相同,但是在分離的pacakges中(它不常見,但可能發生):

首先枚舉

package first.pckg

public enum Category {
    JAZZ,
    ROCK,
    POP,
    POP_ROCK
}

第二枚枚舉:

package second.pckg

public enum Category {
    JAZZ,
    ROCK,
    POP,
    POP_ROCK
}

然後假設你在item.category使用item.category中的下一個item.category ,但是導入第二second.pckg.Category枚舉( second.pckg.Category )而不是第一枚枚舉:

import second.pckg.Category;
...

Category.JAZZ.equals(item.getCategory())

所以你會得到allways false因為是不同的枚舉,雖然你期望真實,因為item.getCategory()JAZZ 。 這可能有點難以看到。

所以,如果你改用運算符==你將會有一個編譯錯誤:

運算符==不能應用於“second.pckg.Category”,“first.pckg.Category”

import second.pckg.Category; 
...

Category.JAZZ == item.getCategory() 

正如其他人所說,在大多數情況下, ==.equals()工作。 編譯時的確定性,你沒有比較其他人指出的完全不同類型的對像是有效和有益的,但是FindBugs也可以找到比較兩種不同編譯時類型對象的特定類型的bug(可能是Eclipse / IntelliJ編譯時間檢查),所以Java編譯器發現它並不會增加額外的安全性。

然而:

  1. ==從來沒有拋出NPE的事實是==缺點 。 幾乎不需要enum類型為null ,因為您可能想要通過null表示的任何額外狀態都可以作為附加實例添加到enum中。 如果它意外為null ,我寧願有一個NPE而不是==默默評估為false。 所以我不同意它在運行時的意見是更安全的 ; 最好不要讓enum值為@Nullable
  2. == 更快的論點也是假的。 在大多數情況下,您會在編譯時類型為enum類的變量上調用.equals() ,在這種情況下,編譯器可以知道這與==相同(因為enumequals()方法可以不被覆蓋)並且可以優化功能呼叫。 我不確定編譯器目前是否這樣做,但如果不這樣做,並且總體上是Java性能問題,那麼我寧願修復編譯器,也不願意讓100,000個Java程序員改變他們的編程風格以適應一個特定的編譯器版本的性能特徵。
  3. enums是對象。 對於所有其他對像類型,標準比較是.equals() ,而不是== 。 我認為對enums進行例外是很危險的,因為您最終會意外地將對象與==而不是equals()相比較,特別是如果您將enum重構為非枚舉類。 在這種重構的情況下,上面的工作點是錯誤的。 要說服你自己使用==是正確的,你需要檢查有問題的值是一個enum還是一個原語; 如果它是一個非enum類,那就錯了,但很容易錯過,因為代碼仍然會編譯。 當使用.equals()會出錯時,唯一的情況是所討論的值是基元; 在那種情況下,代碼不會編譯,所以很難錯過。 因此, .equals()更容易識別為正確的,並且對未來的重構更安全。

我實際上認為Java語言應該已經在Object上定義了==來調用左側值的.equals(),並且為對象標識引入了一個單獨的運算符,但這不是Java定義的方式。

總之,我仍然認為參數贊成使用enum類型的.equals()


總之,兩者都有優點和缺點。

一方面,使用==具有優勢,正如其他答案中所述。

另一方面,如果你出於任何原因用不同的方法(普通類實例)替換枚舉,那麼使用==咬你。 (BTDT)。





enums