Java में Enum फाइनल पर तुलना क्यों की जाती है?


93

जावा में एक एनम Comparableइंटरफ़ेस को लागू करता है। यह ओवरराइड के लिए अच्छा हो गया होता Comparableकी compareToविधि, लेकिन यहाँ यह अंतिम के रूप में चिह्नित है। पर डिफ़ॉल्ट प्राकृतिक व्यवस्था Enumके compareToसूचीबद्ध क्रम है।

क्या किसी को पता है कि जावा एनम में यह प्रतिबंध क्यों है?


वहाँ प्रभावी जावा में एक बहुत अच्छी व्याख्या है - आइटम 10 में 3 संस्करण (बराबर के साथ काम), लेकिन आइटम 14 में वे तुलना के साथ समस्या बताओ () एक ही है)। संक्षेप में: यदि आप एक तात्कालिक श्रेणी का विस्तार करते हैं (जैसे एक एनम) और एक मान घटक जोड़ते हैं, तो आप बराबरी (या तुलना) अनुबंध को संरक्षित नहीं कर सकते।
ईसाई एच। कुह्न

जवाबों:


121

निरंतरता के लिए मुझे लगता है ... जब आप एक enumप्रकार देखते हैं , तो आप एक तथ्य के लिए जानते हैं कि इसकी प्राकृतिक व्यवस्था वह क्रम है जिसमें स्थिरांक घोषित किए जाते हैं।

इसे हल करने के लिए, आप आसानी से अपना खुद का बना सकते हैं Comparator<MyEnum>और जब भी आपको एक अलग आदेश की आवश्यकता होती है, तब इसका उपयोग कर सकते हैं :

enum MyEnum
{
    DOG("woof"),
    CAT("meow");

    String sound;    
    MyEnum(String s) { sound = s; }
}

class MyEnumComparator implements Comparator<MyEnum>
{
    public int compare(MyEnum o1, MyEnum o2)
    {
        return -o1.compareTo(o2); // this flips the order
        return o1.sound.length() - o2.sound.length(); // this compares length
    }
}

आप Comparatorसीधे उपयोग कर सकते हैं :

MyEnumComparator c = new MyEnumComparator();
int order = c.compare(MyEnum.CAT, MyEnum.DOG);

या इसका उपयोग संग्रह या सरणियों में करें:

NavigableSet<MyEnum> set = new TreeSet<MyEnum>(c);
MyEnum[] array = MyEnum.values();
Arrays.sort(array, c);    

अग्रिम जानकारी:


कस्टम तुलना केवल एक संग्रह के लिए Enum आपूर्ति करते समय वास्तव में प्रभावी हैं। यदि आप सीधी तुलना करना चाहते हैं तो यह उतना मदद नहीं करता है।
मार्टिन ओकोनर

7
हाँ यह करता है। new MyEnumComparator.compare (enum1, enum2)। Et voilá।
बॉम्बे

@martinoconnor & Bombe: मैंने आपकी टिप्पणियों को उत्तर में शामिल किया है। धन्यवाद!
ज़च स्क्रिपवेन

चूंकि MyEnumComparatorकोई राज्य नहीं है, यह सिर्फ एक सिंगलटन होना चाहिए, खासकर यदि आप ऐसा कर रहे हैं जो @Bombe सुझाव देता है; इसके बजाय, आप MyEnumComparator.INSTANCE.compare(enum1, enum2)अनावश्यक वस्तु निर्माण से बचने के लिए कुछ करना पसंद करेंगे
kbolino

2
@kbolino: तुलनित्र एनम वर्ग के अंदर एक नेस्टेड वर्ग हो सकता है। यह एक LENGTH_COMPARATORस्थिर क्षेत्र में एनम में संग्रहीत किया जा सकता है । इस तरह से किसी भी व्यक्ति के लिए यह जानना आसान होगा कि वह एनम का उपयोग कर रहा है।
Lii

39

तुलना-आदेश का उपयोग करने वाले डिफ़ॉल्‍ट-कोड ऑर्डर का डिफ़ॉल्ट क्रियान्वयन प्रदान करना ठीक है; इसे अंतिम रूप देना सूर्य की ओर से एक गलत कदम था। अध्यादेश पहले से ही घोषणा के आदेश के लिए जिम्मेदार है। मैं मानता हूं कि ज्यादातर स्थितियों में एक डेवलपर तार्किक रूप से अपने तत्वों का आदेश दे सकता है, लेकिन कभी-कभी कोई स्रोत कोड को इस तरह से व्यवस्थित करना चाहता है जो पठनीयता और रखरखाव को सर्वोपरि बनाता है। उदाहरण के लिए:


  //===== SI BYTES (10^n) =====//

  /** 1,000 bytes. */ KILOBYTE (false, true,  3, "kB"),
  /** 106 bytes. */   MEGABYTE (false, true,  6, "MB"),
  /** 109 bytes. */   GIGABYTE (false, true,  9, "GB"),
  /** 1012 bytes. */  TERABYTE (false, true, 12, "TB"),
  /** 1015 bytes. */  PETABYTE (false, true, 15, "PB"),
  /** 1018 bytes. */  EXABYTE  (false, true, 18, "EB"),
  /** 1021 bytes. */  ZETTABYTE(false, true, 21, "ZB"),
  /** 1024 bytes. */  YOTTABYTE(false, true, 24, "YB"),

  //===== IEC BYTES (2^n) =====//

  /** 1,024 bytes. */ KIBIBYTE(false, false, 10, "KiB"),
  /** 220 bytes. */   MEBIBYTE(false, false, 20, "MiB"),
  /** 230 bytes. */   GIBIBYTE(false, false, 30, "GiB"),
  /** 240 bytes. */   TEBIBYTE(false, false, 40, "TiB"),
  /** 250 bytes. */   PEBIBYTE(false, false, 50, "PiB"),
  /** 260 bytes. */   EXBIBYTE(false, false, 60, "EiB"),
  /** 270 bytes. */   ZEBIBYTE(false, false, 70, "ZiB"),
  /** 280 bytes. */   YOBIBYTE(false, false, 80, "YiB");

उपरोक्त आदेश स्रोत कोड में अच्छा लग रहा है, लेकिन ऐसा नहीं है कि लेखक का मानना ​​है कि तुलना करना चाहिए। वांछित तुलना व्यवहार को बाइट्स की संख्या के अनुसार क्रमबद्ध करना है। स्रोत-कोड आदेश जो ऐसा करेगा जो कोड के संगठन को नीचा दिखाता है।

एक गणना के एक ग्राहक के रूप में मैं कम परवाह नहीं कर सकता कि लेखक ने अपने स्रोत कोड को कैसे व्यवस्थित किया। मैं उनकी तुलना एल्गोरिथ्म को किसी तरह की समझ बनाना चाहता हूं, हालांकि। सूर्य ने अनावश्यक रूप से स्रोत कोड लेखकों को एक बाँध में रखा है।


3
सहमत हूं, मैं चाहता हूं कि मेरी दुश्मनी एक आदेश के बजाय एक व्यापार तुलनीय अल्गोरिथम होने में सक्षम हो, जिसे अगर किसी ने ध्यान नहीं दिया तो उसे तोड़ा जा सकता है।
द बाकरर 16

6

गणना मूल्यों को ठीक-ठीक क्रमबद्ध रूप से उनके द्वारा घोषित किए गए आदेश के अनुसार दिया जाता है। यह जावा लैंग्वेज स्पेसिफिकेशन का हिस्सा है। इसलिए यह अनुसरण करता है कि गणना मूल्यों की तुलना केवल तभी की जा सकती है जब वे एक ही एनम के सदस्य हों। विनिर्देश आगे गारंटी देना चाहता है कि तुलनीय क्रम की तुलना तुर्ती () द्वारा की गई है उसी क्रम में है जिस क्रम में मूल्यों को घोषित किया गया था। यह एक गणना की परिभाषा है।


जैसा कि थॉमस पाइन ने अपने उदाहरण में स्पष्ट किया है, भाषा केवल वाक्य-रचना द्वारा आदेश दे सकती है, शब्दार्थ नहीं। आप कहते हैं, आइटम को तार्किक रूप से ऑर्डर किया जाता है , लेकिन जिस तरह से मैं एनम को समझता हूं, आइटम तार्किक साधनों द्वारा समझाया जाता है।
बॉन्डैक्स

2

एक संभावित व्याख्या यह है कि compareToइसके अनुरूप होना चाहिए equals

और equalsएनमों को पहचान समानता ( ==) के अनुरूप होना चाहिए ।

यदि compareToगैर-अंतिम होना कहां है तो इसे एक ऐसे व्यवहार के साथ ओवरराइड करना संभव होगा जो सुसंगत नहीं था equals, जो बहुत ही सहज ज्ञान युक्त होगा।


हालांकि यह अनुशंसा की जाती है कि तुलना () समतुल्य के अनुरूप है (), यह आवश्यक नहीं है।
क्रिश्चियन एच। कुह्न

-1

यदि आप अपने enum के तत्वों के प्राकृतिक क्रम को बदलना चाहते हैं, तो स्रोत कोड में उनके क्रम को बदलें।


हाँ, यही मैंने मूल प्रविष्टि में लिखा है :)
neu242

हां, लेकिन आप वास्तव में यह नहीं समझाते हैं कि आप तुलना () से आगे क्यों बढ़ना चाहते हैं। तो मेरा निष्कर्ष यह था कि आप कुछ बुरा करना चाहते हैं और मैं आपको अधिक सही तरीका दिखाने की कोशिश कर रहा था।
बॉम्बे

मैं यह नहीं देखता कि मुझे जब कंप्यूटर अपने से बहुत बेहतर काम करता है, तो मुझे हाथ से प्रविष्टियों को क्यों छाँटना चाहिए।
neu242

गणना में यह माना जाता है कि आपने एक कारण से उस विशिष्ट तरीके से प्रविष्टियों का आदेश दिया है। यदि कोई कारण नहीं है तो आप <enum> .toString ()। ComparTo () का उपयोग करके बेहतर हैं। या शायद पूरी तरह से कुछ अलग, शायद एक सेट की तरह?
बॉम्बे

इसका कारण यह है कि मेरे पास Enum के साथ {isocode, countryname} है। इसे मैन्युअल रूप से कंट्रीनाम पर सॉर्ट किया गया था, जो इरादा के अनुसार काम करता है। क्या होगा अगर मैं तय करता हूं कि मैं अब से आइसोडोड पर सॉर्ट करना चाहता हूं?
neu242
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.