क्या जावा में enums पर == का उपयोग करना ठीक है?


111

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

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

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
}


@ कसीलस यह सवाल सबसे पहले आया। शायद flag ध्यान के लिए झंडा, क्योंकि मुझे यकीन नहीं है कि अगर दोनों को मिला दिया जाना चाहिए।
मैट बॉल

@MattBall मुझे लगता है कि आपके प्रश्न का उत्तर जो JLS को उद्धृत करता है, वह सबसे अच्छा उत्तर है, यही वजह है कि मैंने इसे बंद करने का विकल्प चुना।
अस्वस्थ

जवाबों:


149

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

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;
    }


}

4
धन्यवाद! मुझे लगता है कि अगर मैंने संकलक के साथ (।) में कदम रखने के बारे में सोचा था, तो मैंने यह देखा होगा ...
किप

77

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

हालाँकि, आपके राउंड मेथड को लिखने का एक बेहतर तरीका है:

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

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

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

एक Enum प्रकार के शरीर में enum स्थिरांक हो सकते हैं। एक enum निरंतर enum प्रकार की आवृत्ति को परिभाषित करता है। एक एनुम प्रकार का कोई अन्य उदाहरण नहीं है, जो इसके एनम स्थिरांक द्वारा परिभाषित है।


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

विभिन्न मामलों के बीच ओवरलैप होने पर स्विच उपयोगी नहीं होता है। इसके अलावा, RoundingMode java.math का हिस्सा है, इसलिए मैं इसमें कोई विधि नहीं जोड़ सकता।
किप

2
ओह-- और आपको जॉन स्कीट पर संदेह है? आप यहां बहुत लंबे समय तक नहीं रहे हैं;)
जोएल कोएहॉर्न

स्विच स्टेटमेंट में एनम? पता नहीं था कि संभव था। मुझे एक दिन इसे आज़माना होगा।
21

अमूर्त विधियों का उपयोग करके एनमों के भीतर तर्क को दोहराना एनमों की वास्तविक शक्ति है। यह आपके कोड को और अधिक मजबूत बनाता है; जब आप भविष्य में एक नया enum मान जोड़ते हैं, तो कंपाइलर आपको संबंधित तर्क को लागू करने के लिए मजबूर करेगा, आपको कई स्विच स्टेटमेंट में केस जोड़ने के लिए याद नहीं करना होगा।
एंड्रयू स्वान

13

हां, यह ऐसा है जैसे आपने एनम में प्रत्येक मान के लिए सिंगलटन इंस्टेंस बनाया है:

सार्वजनिक सार वर्ग RoundingMode {
  सार्वजनिक स्थैतिक अंतिम RoundMMode HALF_UP = नया RoundingMode ();
  सार्वजनिक स्थैतिक अंतिम RoundMMode HALF_EVEN = नया RoundingMode ();

  निजी राउंडमोड () {
    // निजी गुंजाइश इस वर्ग के बाहर किसी भी उपप्रकार को रोकता है
  }
}

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

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

सीरियलाइजेशन एक बड़ी गोटिया है। अगर मैं एक एनम के बजाय ऊपर दिए गए कोड का उपयोग कर रहा था, तो यहां बताया गया है कि समानता की पहचान कैसे होगी:

RoundingMode मूल = RoundingMode.HALF_UP;
मुखर (RoundingMode.HALF_UP == मूल); // गुजरता

ByteArrayOutputStream baos = new ByteArrayOutputStream ();
ObjectOutputStream oos = new ObjectOutputStream (baos);
oos.writeObject (मूल);
oos.flush ();

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

मुखर (RoundingMode.HALF_UP == deserialized); // विफल रहता है
मुखर (RoundingMode.HALF_EVEN == deserialized); // विफल रहता है

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

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


1
क्रमबद्धता बग तय की गई थी। Bugs.sun.com/bugdatabase/view_bug.do?bug_id=6277781
डेविड आई।

@DavidI। अद्यतन के लिए धन्यवाद। यह एक बहुत परेशान करने वाला बग है, और यह जानना अच्छा है!
Dilum Ranatunga

1
@DilumRanatunga मुझे लगा कि यह मुझे पहली बार प्रभावित करने वाला है, लेकिन वे RMI कनेक्शन पर उन्हें पास करने के बाद ठीक काम कर रहे हैं।
डेविड आई।

11

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

संदर्भ:

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
@ आप इस कोड के आयात को शामिल कर सकते हैं? घाव नहीं मिला Unsafe.class
Rumman0786

3

पॉलीमोर्फिक कोड को जाम करने के लिए एनम एक शानदार जगह है।

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 नहीं है, इसलिए मैं अपने मामले में ऐसा नहीं कर सकता।
किप


0

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

जावा एनम सदस्यों की तुलना: == या बराबर ()?

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.