2009-02-10 14 views
85

क्या जावा में enums पर == का उपयोग करना ठीक है, या मुझे .equals() का उपयोग करने की आवश्यकता है? मेरे परीक्षण में, == हमेशा काम करता है, लेकिन मुझे यकीन नहीं है कि मुझे इसकी गारंटी है या नहीं। विशेष रूप से, एनम पर .clone() विधि नहीं है, इसलिए मुझे नहीं पता कि एनम प्राप्त करना संभव है जिसके लिए .equals()== से भिन्न मान लौटाएगा।क्या जावा में enums पर == का उपयोग करना ठीक है?

उदाहरण के लिए, यह ठीक है:

public int round(RoundingMode roundingMode) { 
    if(roundingMode == RoundingMode.HALF_UP) { 
    //do something 
    } else if (roundingMode == RoundingMode.HALF_EVEN) { 
    //do something 
    } 
    //etc 
} 

या मैं इसे इस तरह लिखने के लिए की जरूरत है:

public int round(RoundingMode roundingMode) { 
    if(roundingMode.equals(RoundingMode.HALF_UP)) { 
    //do something 
    } else if (roundingMode.equals(RoundingMode.HALF_EVEN)) { 
    //do something 
    } 
    //etc 
} 
+4

के संभावित डुप्लिकेट [जावा enum सदस्यों की तुलना: == या इसके बराबर()] (http://stackoverflow.com/questions/1750435/comparing-java-enum-members -या-बराबर) – assylias

+0

@assylias यह सवाल पहले आया था। शायद ♦ ध्यान के लिए ध्वज, क्योंकि मुझे सच में यकीन नहीं है कि दोनों को विलय किया जाना चाहिए। –

+0

@ मैटबॉल मुझे लगता है कि जेएलएस का उद्धरण आपके प्रश्न का उत्तर सबसे अच्छा जवाब है, इसलिए मैंने इसे बंद करना चुना है। – assylias

उत्तर

117

बस मेरे 2 सेंट: यहाँ, के रूप में सूर्य द्वारा प्रकाशित, Enum.java के लिए कोड है और जेडीके का हिस्सा:

public abstract class Enum<E extends Enum<E>> 
    implements Comparable<E>, Serializable { 

    // [...] 

    /** 
    * 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. 
    */ 
    public final boolean equals(Object other) { 
     return this==other; 
    } 


} 
+1

धन्यवाद! मुझे लगता है कि अगर मैंने संकलक के साथ .equals() में कदम रखा था तो मैंने इसे देखा होगा ... – Kip

70

हाँ, == ठीक है - वहाँ सिर्फ एक संदर्भ होने की गारंटी है प्रत्येक मूल्य के लिए।

हालांकि, वहाँ अपने दौर विधि लेखन का एक बेहतर तरीका है:

public int round(RoundingMode roundingMode) { 
    switch (roundingMode) { 
    case HALF_UP: 
     //do something 
     break; 
    case HALF_EVEN: 
     //do something 
     break; 
    // etc 
    } 
} 

एक भी बेहतर यह enum के भीतर ही कार्यक्षमता डाल करने के लिए है ऐसा करने का तरीका है, तो आप सिर्फ roundingMode.round(someValue) कह सकते हैं। यह जावा enums के दिल में हो जाता है - वे ऑब्जेक्ट उन्मुख enums हैं, कहीं और "नामित मूल्य" के विपरीत।

संपादित करें: कल्पना बहुत स्पष्ट नहीं है, लेकिन section 8.9 कहता है:

एक enum प्रकार के शरीर enum स्थिरांक हो सकती है। एक enum स्थिर enum प्रकार का एक उदाहरण परिभाषित करता है। एनम प्रकार के के किसी भी प्रकार के उदाहरण हैं, जो इसके enum स्थिरांक द्वारा परिभाषित किए गए हैं।

+0

मुझे इसके लिए अपना शब्द लेना अच्छा लगेगा, लेकिन अगर आप कुछ आधिकारिक दस्तावेज के लिए एक लिंक प्रदान कर सकते हैं जो बेहतर होगा ... – Kip

+0

स्पेक या जावा डॉक्स के प्रासंगिक बिट की तलाश करेगा। –

+0

क्या यह ठीक है? वह पूरी तरह से बात है! विभिन्न मामलों के बीच बहुत अधिक ओवरलैप होने पर –

10

== दो वस्तुओं के संदर्भों की तुलना करता है। Enums के लिए, यह गारंटी है कि केवल एक उदाहरण होगा, और इसलिए किसी भी दो enums के लिए, == सच हो जाएगा।

संदर्भ:

http://www.ajaxonomy.com/2007/java/making-the-most-of-java-50-enum-tricks

(सूर्य डॉक्स में कुछ भी नहीं मिला)

6

यहां कुछ बुरा कोड है जो आपको दिलचस्प लग सकता है। : डी

public enum YesNo {YES, NO} 

public static void main(String... args) throws Exception { 
    Field field = Unsafe.class.getDeclaredField("theUnsafe"); 
    field.setAccessible(true); 
    Unsafe unsafe = (Unsafe) field.get(null); 
    YesNo yesNo = (YesNo) unsafe.allocateInstance(YesNo.class); 

    Field name = Enum.class.getDeclaredField("name"); 
    name.setAccessible(true); 
    name.set(yesNo, "YES"); 

    Field ordinal = Enum.class.getDeclaredField("ordinal"); 
    ordinal.setAccessible(true); 
    ordinal.set(yesNo, 0); 

    System.out.println("yesNo " + yesNo); 
    System.out.println("YesNo.YES.name().equals(yesNo.name()) "+YesNo.YES.name().equals(yesNo.name())); 
    System.out.println("YesNo.YES.ordinal() == yesNo.ordinal() "+(YesNo.YES.ordinal() == yesNo.ordinal())); 
    System.out.println("YesNo.YES.equals(yesNo) "+YesNo.YES.equals(yesNo)); 
    System.out.println("YesNo.YES == yesNo " + (YesNo.YES == yesNo)); 
} 
+1

बुरा मत बनो! बीटीडब्ल्यू, आप स्ट्रिंग्स के साथ एक ही काम कर सकते हैं जो प्रशिक्षित हैं ... – Chii

11

हाँ, यह है के रूप में यदि आप enum में प्रत्येक मान के लिए सिंगलटन उदाहरणों बनाया था:

 
public abstract class RoundingMode { 
    public static final RoundingMode HALF_UP = new RoundingMode(); 
    public static final RoundingMode HALF_EVEN = new RoundingMode(); 

    private RoundingMode() { 
    // private scope prevents any subtypes outside of this class 
    } 
} 

हालांकि, enum निर्माण आप देता है विभिन्न लाभों:

  • प्रत्येक इंस्टेंस की ToString() कोड में दिए गए नाम को प्रिंट करता है।
  • (जैसा कि किसी अन्य पोस्ट में उल्लिखित है), enum प्रकार के एक चर को switch-case नियंत्रण संरचना का उपयोग कर स्थिरांक के विरुद्ध तुलना की जा सकती है।
  • सभी गणना में मानों values क्षेत्र है कि प्रत्येक enum प्रकार
  • के लिए 'उत्पन्न' का उपयोग पूछे जा सकती है, यहाँ बड़ी w.r.t पहचान तुलना है: enum मूल्यों क्लोनिंग के बिना क्रमबद्धता जीवित रहते हैं।

क्रमबद्धता एक बड़ा गॉच्य है। अगर मैं एक enum के बजाय ऊपर कोड का उपयोग करने के लिए गए थे, तो यहां आपको पहचान समानता कैसा व्यवहार करेंगे है:, enum के बिना इस मुद्दे

 
RoundingMode original = RoundingMode.HALF_UP; 
assert (RoundingMode.HALF_UP == original); // passes 

ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
ObjectOutputStream oos = new ObjectOutputStream(baos); 
oos.writeObject(original); 
oos.flush(); 

ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); 
ObjectInputStream ois = new ObjectInputStream(bais); 
RoundingMode deserialized = (RoundingMode) ois.readObject(); 

assert (RoundingMode.HALF_UP == deserialized); // fails 
assert (RoundingMode.HALF_EVEN == deserialized); // fails 

आप कर सकते हैं पते में एक तकनीक है कि writeReplace और readResolve शामिल है का उपयोग करते हुए, (http://java.sun.com/j2se/1.4.2/docs/api/java/io/Serializable.html देखें) ...

मुझे लगता है कि बिंदु यह है - जावा आपके रास्ते से बाहर निकलता है ताकि आप समानता परीक्षण के लिए enum मानों की पहचान का उपयोग कर सकें; यह एक प्रोत्साहित अभ्यास है।

+1

+1 क्रमबद्धता पर महान नोट –

+1

क्रमबद्धता बग तय किया गया था। http://bugs.sun.com/bugdatabase/view_bug.do?bug_id = 6277781 –

+0

@ डेविडआई। अद्यतन के लिए धन्यवाद। यह एक बहुत परेशान करने वाली बग है, और जानना अच्छा है! –

3

Enums जाम polymorphic कोड के लिए एक महान जगह है।

enum Rounding { 
    ROUND_UP { 
    public int round(double n) { ...; } 
    }, 
    ROUND_DOWN { 
    public int round(double n) { ...; } 
    }; 

    public abstract int round(double n); 
} 

int foo(Rounding roundMethod) { 
    return roundMethod.round(someCalculation()); 
} 

int bar() { 
    return foo(Rounding.ROUND_UP); 
} 
+1

हां लेकिन मेरे पास java.math.RoundingMode नहीं है, इसलिए मैं इसे अपने मामले में नहीं कर सकता। – Kip

1

ध्यान दें कि आरएमआई/IIOP के माध्यम से enum transfering करते समय समस्या है। इस सूत्र देखें:

http://www.velocityreviews.com/forums/t390342-enum-equality.html

+1

यह http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6277781 था जो अब तय किया गया है। –

1

== आम तौर पर ठीक है, और वहाँ दोनों == और .equals() को लाभ हैं। enum एस सहित ऑब्जेक्ट की तुलना करते समय मैं व्यक्तिगत रूप से .equals() का उपयोग करना पसंद करता हूं। यह भी देखें इस चर्चा:

Comparing Java enum members: == or equals()?

संबंधित मुद्दे