Java enum में valueofof () और toString () को ओवरराइड करें


122

मेरे मूल्य enumशब्द ऐसे शब्द हैं जिनके लिए रिक्त स्थान होना आवश्यक है, लेकिन एनमों के पास अपने मूल्यों में रिक्त स्थान नहीं हो सकते हैं, इसलिए यह सब कुछ समाप्त हो गया है। मैं toString()इन जगहों को जोड़ने के लिए ओवरराइड करना चाहता हूं जहां मैं इसे बताता हूं।

मैं यह भी चाहता हूं कि जब मैं valueOf()उसी स्ट्रिंग पर उपयोग करता हूं, जिसमें मैंने रिक्त स्थान जोड़ा है, तो मैं सही एनम प्रदान करना चाहता हूं।

उदाहरण के लिए:

public enum RandomEnum
{
     StartHere,
     StopHere
}

जिसका मूल्य रिटर्न स्ट्रिंग है उस toString()पर कॉल करें । उसी स्ट्रिंग पर कॉल करें ( ) एनम मान लौटाता है ।RandomEnumStartHere"Start Here"valueof()"Start Here"StartHere

मैं यह कैसे कर सकता हूँ?


2
अधिक टिप्पणियां / उत्तर पाने के लिए "जावा" टैग जोड़ें।
जावा ४२

जवाबों:


197

आप इस कोड को आज़मा सकते हैं। चूंकि आप valueOfविधि को ओवरराइड नहीं कर सकते हैं इसलिए आपको एक कस्टम विधि ( getEnumनीचे दिए गए नमूना कोड में) को परिभाषित करना होगा जो आपको आवश्यक मान लौटाता है और इस पद्धति का उपयोग करने के लिए अपने क्लाइंट को बदले।

public enum RandomEnum {

    StartHere("Start Here"),
    StopHere("Stop Here");

    private String value;

    RandomEnum(String value) {
        this.value = value;
    }

    public String getValue() {
        return value;
    }

    @Override
    public String toString() {
        return this.getValue();
    }

    public static RandomEnum getEnum(String value) {
        for(RandomEnum v : values())
            if(v.getValue().equalsIgnoreCase(value)) return v;
        throw new IllegalArgumentException();
    }
}

4
getEnum को छोटा किया जा सकता है यदि आप निम्न कार्य करते हैं: v.getValue ()। बराबर (मान); अशक्त जाँच को छोड़ा जा सकता है।
rtcarlson

आप आलसी रूप से एक नक्शा बना सकते हैं और उसका पुन: उपयोग कर सकते हैं, लेकिन इसे बनाते समय थ्रेडिंग मुद्दों से सावधान रहें।
मार्टन बोडेवेस

11
ऐसे परिदृश्य में काम नहीं करता है जहाँ आप valueOf () पद्धति को getValue () में बदलने के लिए कॉल नहीं कर सकते हैं। उदाहरण के लिए जब आप हाइबरनेट एनोटेशन के माध्यम से कुछ क्षेत्रों को परिभाषित करते हैं ताकि मानों को
बढ़ाया जा

जब तक Enums जावा में तय नहीं हो जाते, तब तक @Bat के पास अधिक उपयुक्त और OO अनुकूल समाधान है। नाम () अंतिम नहीं होना चाहिए।
एंड्रयू टी फिनेल

इसके बजाय आप valueOf (randomEnum.class, value) का उपयोग कर सकते हैं;
वोजटेक

22

यह कोशिश करो, लेकिन मुझे यकीन नहीं है कि हर जगह काम करेगा :)

public enum MyEnum {
    A("Start There"),
    B("Start Here");

    MyEnum(String name) {
        try {
            Field fieldName = getClass().getSuperclass().getDeclaredField("name");
            fieldName.setAccessible(true);
            fieldName.set(this, name);
            fieldName.setAccessible(false);
        } catch (Exception e) {}
    }
}

18
मैं ऐसा क्यों हूं जो केवल उसी तरह का सामान है जो बुराई को देखता है? मेरा मतलब है कि यह वास्तव में अच्छा लग रहा है, लेकिन कोई भी ऐसा व्यक्ति जो किसी संदर्भ के साथ नहीं पढ़ता है, वह कोड "डब्ल्यूटीएफ" की तरह होगा।
निकोलस गिलाइम

11
@ निकोलसगिल्यूम ऐसा कोड है, जिसे यदि लागू किया जाता है, तो उसे यह बताने की सख्त जरूरत होगी कि यह क्यों है और प्रोग्रामर किस समस्या को हल करने की कोशिश कर रहा है। :-)
तिवारी स्ट्रगा

9
सामान्य अपवाद को न
पकड़ें

2
यह एक भयानक विचार है। नहीं संकेत या वसूली के साथ मूक त्रुटि के लिए संभावना कम से कम नहीं है। अब भी कोड में "नाम" मान और प्रतीकात्मक मूल्य (जैसे ए, बी) अलग हैं। +2 चतुर होने के लिए। -200 बहुत चालाक होने के लिए। ऐसा कोई तरीका नहीं है जिससे मैं कभी भी कोड समीक्षा की मंजूरी दूं।
पेडोरो

1
@pedorro यह उतना भयानक नहीं लगता जितना आप इसे बनाने के लिए बना रहे हैं। किसी ने भी समझा कि सब कुछ जावा समिति को नहीं लेना चाहिए क्योंकि सुसमाचार एक कोड समीक्षा में इसे पारित करेगा। यह असीम रूप से बदतर है फिर से लिखना और फिर एनम उपयोगिता के सभी तरीकों को बनाए रखना, क्योंकि नाम () को ओवरराइड नहीं किया जा सकता है। अपवाद को पकड़ने और इसे निगलने के बजाय, एक RuntimeException को फेंक दिया जाना चाहिए और फिर यह ठीक है।
एंड्रयू टी फिनेल

14

आप अपने एनम में एक स्थिर मानचित्र का उपयोग कर सकते हैं जो स्ट्रिंग्स को एनम स्थिरांक को मैप करता है। 'GetEnum' स्टैटिक विधि में इसका उपयोग करें। यह हर बार जब आप अपने स्ट्रिंग मूल्य से एक प्राप्त करना चाहते हैं, तो एनम के माध्यम से पुनरावृति करने की आवश्यकता को पूरा करता है।

public enum RandomEnum {

    StartHere("Start Here"),
    StopHere("Stop Here");

    private final String strVal;
    private RandomEnum(String strVal) {
        this.strVal = strVal;
    }

    public static RandomEnum getEnum(String strVal) {
        if(!strValMap.containsKey(strVal)) {
            throw new IllegalArgumentException("Unknown String Value: " + strVal);
        }
        return strValMap.get(strVal);
    }

    private static final Map<String, RandomEnum> strValMap;
    static {
        final Map<String, RandomEnum> tmpMap = Maps.newHashMap();
        for(final RandomEnum en : RandomEnum.values()) {
            tmpMap.put(en.strVal, en);
        }
        strValMap = ImmutableMap.copyOf(tmpMap);
    }

    @Override
    public String toString() {
        return strVal;
    }
}

बस यह सुनिश्चित कर लें कि नक्शा का स्थैतिक आरम्भ ऐनुम स्थिरांक की घोषणा के नीचे होता है।

BTW - वह 'ImmutableMap' प्रकार Google अमरूद एपीआई से है, और मैं निश्चित रूप से इस तरह के मामलों में इसकी सिफारिश करता हूं।


EDIT - टिप्पणियों के अनुसार:

  1. यह समाधान मानता है कि प्रत्येक निर्दिष्ट स्ट्रिंग मान अद्वितीय और गैर-शून्य है। यह देखते हुए कि एनम के निर्माता इसे नियंत्रित कर सकते हैं, और यह कि स्ट्रिंग अद्वितीय और गैर-शून्य एनम मान से मेल खाती है, यह एक सुरक्षित प्रतिबंध की तरह लगता है।
  2. मैंने 'toSTring ()' विधि को प्रश्न में पूछा है

1
मुझे इस उत्तर पर कुछ मत मिले हैं - किसी को भी इस बात का ध्यान रखना चाहिए कि यह उत्तर खराब क्यों है? मैं बस उत्सुक हूं कि लोग क्या सोच रहे हैं।
पाद्रो

यह उसी तरह के 'मान' के साथ कई Enum स्थिरांक वाले परिदृश्य के लिए विफल होगा, जैसे कि RestartHere("replay"), ReplayHere("replay")या बिल्कुल भी 'मान' नहीं है PauseHere, WaitHere(जैसे कि Enum का डिफ़ॉल्ट private RandomEnum() { this.strVal = null; }
रचनाकार

1
आपको + ImmutableMap :: copyOf बनाने के लिए एक MutableMap बनाने के बजाय ImmutableMap.Builder का उपयोग करना चाहिए।
ब्रायन कॉरेल

यह दिलचस्प लग रहा है, लेकिन अगर एनम के पास केवल कुछ अलग मूल्य हैं तो यह उन पर पुनरावृति करने में लंबा समय नहीं लेगा। यह शायद केवल इसके लायक है अगर एनम में बहुत सारे मूल्य हैं।
बेन थर्ले

13

जावा 8 कार्यान्वयन के बारे में कैसे? (अशक्त को आपके डिफ़ॉल्ट Enum द्वारा प्रतिस्थापित किया जा सकता है)

public static RandomEnum getEnum(String value) {
    List<RandomEnum> list = Arrays.asList(RandomEnum.values());
    return list.stream().filter(m -> m.value.equals(value)).findAny().orElse(null);
}

या आप उपयोग कर सकते हैं:

...findAny().orElseThrow(NotFoundException::new);

2

मुझे नहीं लगता कि आपके काम करने के लिए valueOf ("यहां शुरू करें") जा रहा है। लेकिन जहाँ तक रिक्त स्थान हैं ... निम्नलिखित प्रयास करें ...

static private enum RandomEnum {
    R("Start There"), 
    G("Start Here"); 
    String value;
    RandomEnum(String s) {
        value = s;
    }
}

System.out.println(RandomEnum.G.value);
System.out.println(RandomEnum.valueOf("G").value);

Start Here
Start Here

2

निम्नलिखित मान के लिए एक अच्छा सामान्य विकल्प है ()

public static RandomEnum getEnum(String value) {
  for (RandomEnum re : RandomEnum.values()) {
    if (re.description.compareTo(value) == 0) {
      return re;
    }
  }
  throw new IllegalArgumentException("Invalid RandomEnum value: " + value);
}

स्ट्रिंग्स की compareTo()तुलना में अधिक सुरुचिपूर्ण का उपयोग है equals()?
बेतालिस्टा

लालित्य कोई मुद्दा नहीं है - मैं मानता हूं कि .equals()यह ठीक काम करेगा। ==आप चाहें तो इस्तेमाल कर सकते हैं। (हालांकि अच्छा कारण यह नहीं है कि आपको कभी भी एनम को एक वर्ग के साथ बदलना चाहिए।)
अपवाद

3
स्ट्रिंग की तुलना के लिए @exception का उपयोग करें == क्योंकि यह आपको वस्तु समानता की जाँच करेगा, जबकि आपको जो चाहिए वह है सामग्री समानता की जाँच और इसके लिए स्ट्रिंग क्लास के बराबर () विधि का उपयोग करें।
संचिति

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