जावा में एनम इंटम करें


331

निम्नलिखित में से एनम को जावा में इंट में डालने का सही तरीका क्या है?

public enum MyEnum
{
    EnumValue1,
    EnumValue2
}


MyEnum enumValue = (MyEnum) x; //Doesn't work???

@RyuS। यह इस प्रश्न का डुप्लिकेट नहीं है,
मार्क रोटेवेल

जवाबों:


584

कोशिश करें MyEnum.values()[x]कि कहाँ xहोना चाहिए 0या 1, यानी कि एनम के लिए एक वैध अध्यादेश।

ध्यान दें कि जावा एनम में वास्तव में कक्षाएं हैं (और एनम मान इस प्रकार ऑब्जेक्ट हैं) और इस प्रकार आप एक एनम intया यहां तक Integerकि एक एनम भी नहीं डाल सकते हैं ।


115
+1: आप MyEnum.values()इसके महंगे होने को कैश कर सकते हैं । अगर आप इसे सैकड़ों बार कहते हैं।
पीटर लॉरी

6
@PeterLawrey पूर्णता के लिए, क्या आप बता सकते हैं कि यह धीमा क्यों होना चाहिए? मुझे इसका कोई स्पष्ट कारण नहीं दिख रहा है।
तारासच

48
@ सारणी के रूप में सारणी परिवर्तनशील हैं, मान () तत्वों के सरणी की एक प्रति वापस लौटना चाहिए, यदि आप इसे बदलने के लिए होते हैं। इस प्रति को बनाना हर बार अपेक्षाकृत महंगा होता है।
पीटर लॉरी

9
@PeterLawrey मैं हाल ही में बहुत अधिक हैस्केल का उपयोग कर रहा हूं (जहां सब कुछ अपरिवर्तनीय है)! आपके स्पष्ट और संक्षिप्त विवरण के लिए धन्यवाद। :)
१०:४६

'x' कैसे प्राप्त करें?
मधुमक्खी जेक

160

MyEnum.values()[x]एक महंगा ऑपरेशन है। यदि प्रदर्शन एक चिंता का विषय है, तो आप कुछ इस तरह से करना चाह सकते हैं:

public enum MyEnum {
    EnumValue1,
    EnumValue2;

    public static MyEnum fromInteger(int x) {
        switch(x) {
        case 0:
            return EnumValue1;
        case 1:
            return EnumValue2;
        }
        return null;
    }
}

44
यदि आप स्विच रखरखाव से बचना चाहते हैं, तो निम्न वर्ग पर: निजी अंतिम MyEnum [] myEnumValues ​​= MyEnum.values ​​(); फिर उपयोग: myEnum = myEnumValues ​​[i];
गिली नचम

23
@ गिलियनाचुम ने इसे एक अजीब तरीके से कहा, लेकिन इस समाधान के साथ समस्या रखरखाव है। यह DRY सिद्धांत के खिलाफ जाता है, जिसका अर्थ है कि जब भी एनम मानों को बदला जाता है (फिर से जोड़ा गया, मूल्य (s) जोड़ा गया, मूल्य (s) हटा दिया गया) स्विच स्टेटमेंट को एक साथ अपडेट किया जाना है। गिली की टिप्पणी जावा को Enum मानों की सूची के साथ स्थिरता बनाए रखने के लिए मजबूर करती है, enum मानों में परिवर्तन उस दृष्टिकोण को बिल्कुल प्रभावित नहीं करता है।
डंड्रे एलीसन

3
@LorenzoPolidori, क्या आप समझा सकते हैं कि आप MyEnum.values()[x]एक महंगे ऑपरेशन के रूप में क्यों मानते हैं । मुझे नहीं पता कि यह विवरण में कैसे काम करता है, लेकिन मेरे लिए ऐसा लगता है कि एरियर में एक तत्व तक पहुंचना कोई बड़ी बात नहीं होगी, निरंतर समय। यदि सरणी का निर्माण करना है तो यह O (n) समय लेता है, जो आपके समाधान के समान रनिंग टाइम है।
ब्रून्सगार्ड

1
@brunsgaard मुझे लगता है कि values()हर बार एक नया सरणी उत्पन्न करता है, क्योंकि सरणियाँ परस्पर हैं इसलिए एक ही समय में एक ही बार वापस करना सुरक्षित नहीं होगा। स्विच स्टेटमेंट आवश्यक रूप से O (n) नहीं हैं, उन्हें टेबल जंप करने के लिए संकलित किया जा सकता है। इसलिए लोरेंजो के दावे जायज लगते हैं।
माइकफहै

1
@ जॉनसन गिल्ली के संस्करण को एनम घोषणा में हुए परिवर्तनों के बाहर किसी अतिरिक्त कोड परिवर्तन की आवश्यकता नहीं है। यदि आप एनम में एक नया आइटम जोड़ते हैं, तब myEnum = myEnumValues[i]भी iबिना बदले एनम में वें आइटम को वापस कर देगा ।
डांड्रे एलीसन

45

यदि आप अपने पूर्णांक मान देना चाहते हैं, तो आप नीचे की तरह एक संरचना का उपयोग कर सकते हैं

public enum A
{
        B(0),
        C(10),
        None(11);
        int id;
        private A(int i){id = i;}

        public int GetID(){return id;}
        public boolean IsEmpty(){return this.equals(A.None);}
        public boolean Compare(int i){return id == i;}
        public static A GetValue(int _id)
        {
            A[] As = A.values();
            for(int i = 0; i < As.length; i++)
            {
                if(As[i].Compare(_id))
                    return As[i];
            }
            return A.None;
        }
}

5
+1 क्योंकि यह इस तथ्य को उजागर करता है, कि मूल्यों को निरंतर नहीं होना चाहिए।
17

इसके अलावा, यह एकमात्र उत्तर प्रतीत होता है जो काम करता है यदि आप 0 से डिफ़ॉल्ट ऑर्डिनल्स का उपयोग करने के बजाय पूर्णांक मानों का एक विरल (या दोहराया) सेट चाहते हैं (गणना -1)। यदि आप मौजूदा कोड के साथ बातचीत कर रहे हैं, तो यह महत्वपूर्ण हो सकता है, जैसे कि नेटवर्क पर।
बेंक

इस बात की ओर इशारा करते हुए कि ऊपर दिए गए जवाबों में मानों के परिणाम को रोकना संभवत: सार्थक है, इसलिए हर बार जब आप इसे लागू करते हैं, तो मेमोरी आवंटन और एरेस्कोपी से बचना चाहिए।
बेंक

1
और, अपने एनम की लंबाई के आधार पर, आप हर बार एक रेखीय खोज करने के बजाए, इस लुकअप के लिए एक HashMap बनाना या द्विआधारी खोज या कुछ का उपयोग करना चाह सकते हैं।
बेंक

2
इंटम को एनम में बदलने के लिए यह सही तरीका और सर्वोत्तम अभ्यास होना चाहिए, और मुझे लगता है कि आप सार्वजनिक स्थैतिक A गेटवैल्यू (int _id) {for (A: A.values) () {if (a.getId) द्वारा समस्या को सरल बना सकते हैं। ) == _ आईडी) {वापसी ए;}} वापसी अशक्त; कोई भी छुटकारा नहीं है, isEmpty () और तुलना () सामान।
क्रिस .Zou

35

आप इस तरह की कोशिश कर सकते हैं।
एलिमेंट आईडी के साथ क्लास बनाएं।

      public Enum MyEnum {
        THIS(5),
        THAT(16),
        THE_OTHER(35);

        private int id; // Could be other data type besides int
        private MyEnum(int id) {
            this.id = id;
        }

        public static MyEnum fromId(int id) {
                for (MyEnum type : values()) {
                    if (type.getId() == id) {
                        return type;
                    }
                }
                return null;
            }
      }

अब इंट के रूप में आईडी का उपयोग करके इस एनम को प्राप्त करें।

MyEnum myEnum = MyEnum.fromId(5);

19

मैं मानों को कैश करता हूं और एक सरल स्टेटिक एक्सेस विधि बनाता हूं:

public static enum EnumAttributeType {
    ENUM_1,
    ENUM_2;
    private static EnumAttributeType[] values = null;
    public static EnumAttributeType fromInt(int i) {
        if(EnumAttributeType.values == null) {
            EnumAttributeType.values = EnumAttributeType.values();
        }
        return EnumAttributeType.values[i];
    }
}

4
यह समाधान है जो मैं अभी उपयोग करता हूं। लेकिन अगर आप फ़ील्ड valuesको विधि के समान नाम नहीं देते हैं तो IMHO कम भ्रमित होता है values()। मैं cachedValuesफ़ील्ड नाम के लिए उपयोग करता हूं ।
टूलमेकर

2
कुशल और सुरुचिपूर्ण; मेरी परियोजना में कॉपी और पेस्ट किया गया :) केवल एक चीज जो मैंने बदली है वह है आईआईएनटी (आईएनटी), जिसे मुझे सिर्फ (इंट आई) से बुलाया जाता है क्योंकि हस्ताक्षर में दो बार इंट होने के लिए यह थोड़ा बेमानी है।
पाइपड्रीमबॉम्ब

1
शुरुआत से क्यों नहीं? पहली हिट का इंतजार क्यों?
kaiser

9

Java enums में एक ही तरह की Enum-to-int मैपिंग नहीं है जो वे C ++ में करते हैं।

उस ने कहा, सभी enums में एक valuesविधि है जो संभावित enum मानों की एक सरणी देता है, इसलिए

MyEnum enumValue = MyEnum.values()[x];

कार्य करना चाहिए। यह थोड़ा बुरा है और यदि संभव हो तो intएस से Enumएस (या इसके विपरीत) की कोशिश न करें और परिवर्तित करने के लिए बेहतर हो सकता है।


9

यह ऐसा कुछ नहीं है जो आमतौर पर किया जाता है, इसलिए मैं पुनर्विचार करूंगा। लेकिन कहा जा रहा है कि, मौलिक संचालन हैं: int -> Enum का उपयोग EnumType.values ​​() [intNum], और enum -> int का उपयोग करते हुए enumInst.ordinal ()।

हालाँकि, मानों के किसी भी क्रियान्वयन () में आपके पास सरणी की एक प्रति देने के अलावा कोई विकल्प नहीं है (जावा सरणियाँ कभी-कभी केवल पढ़ने के लिए नहीं होती हैं), आपको एनुम का उपयोग करने के लिए एनुम -> इंट मैपिंग का उपयोग करना बेहतर होगा।


2
पुन: "यह कुछ ऐसा नहीं है जो आमतौर पर किया जाता है": सामान्य मामला जहां यह उपयोगी है: enum एक डेटाबेस में संग्रहीत इंट मान से मेल खाता है।
टूलमेकर

@ टूलमेकर आप बिल्कुल सही हैं कि मैपिंग की आवश्यकता है। लेकिन क्या आप कुछ या मैपर या कुछ टूलकिट / लाइब्रेरी में एन्कोडिंग को छोड़ना चाहेंगे?
दिलुम रणतुंगा


6

यहाँ समाधान मैं के साथ जाने की योजना है। यह न केवल गैर-अनुक्रमिक पूर्णांक के साथ काम करता है, बल्कि इसे किसी अन्य डेटा प्रकार के साथ काम करना चाहिए जिसे आप अपने एनम मानों के लिए अंतर्निहित आईडी के रूप में उपयोग करना चाहते हैं।

public Enum MyEnum {
    THIS(5),
    THAT(16),
    THE_OTHER(35);

    private int id; // Could be other data type besides int
    private MyEnum(int id) {
        this.id = id;
    }

    public int getId() {
        return this.id;
    }

    public static Map<Integer, MyEnum> buildMap() {
        Map<Integer, MyEnum> map = new HashMap<Integer, MyEnum>();
        MyEnum[] values = MyEnum.values();
        for (MyEnum value : values) {
            map.put(value.getId(), value);
        }

        return map;
    }
}

मुझे केवल आईडी को विशिष्ट समय पर (जब किसी फ़ाइल से डेटा लोड कर रहा है) एनम में परिवर्तित करने की आवश्यकता है, इसलिए मेरे लिए हर समय मानचित्र को याद में रखने का कोई कारण नहीं है। यदि आपको हर समय मानचित्र की आवश्यकता होती है, तो आप इसे हमेशा अपने Enum वर्ग के स्थिर सदस्य के रूप में कैश कर सकते हैं।


IMHO यदि मैं मेमोरी उपयोग के बारे में चिंतित था, तो मैं गतिशील रूप से HashMap बनाएगा - जैसे @ossys लेकिन अलग-अलग कोड के साथ जब कैश शून्य है, तब एक दूसरी विधि जोड़ें clearCachedValuesजब आप इसका उपयोग कर रहे हों (जो कि निजी क्षेत्र को वापस शून्य पर सेट करता है)। मैं MyEnum.fromInt(i)एक मानचित्र वस्तु के आसपास से गुजरने को समझने में आसान मानता हूं ।
टूलमेकर

6

मामले में यह दूसरों की मदद करता है, जो विकल्प मुझे पसंद है, जो यहां सूचीबद्ध नहीं है, अमरूद की मैप्स कार्यक्षमता का उपयोग करता है :

public enum MyEnum {
    OPTION_1(-66),
    OPTION_2(32);

    private int value;
    private MyEnum(final int value) {
        this.value = value;
    }

    public int getValue() {
        return this.value;
    }

    private static ImmutableMap<Integer, MyEnum> reverseLookup = 
            Maps.uniqueIndex(Arrays.asList(MyEnum.values())), MyEnum::getValue);

    public static MyEnum fromInt(final int id) {
        return reverseLookup.getOrDefault(id, OPTION_1);
    }
}

डिफ़ॉल्ट के साथ आप उपयोग कर सकते हैं null, तो आप कर सकते हैं throw IllegalArgumentExceptionया अपने fromIntएक वापसी कर सकता है Optional, जो कुछ भी व्यवहार आप पसंद करते हैं।


3
आपको उल्लेख करना चाहिए कि आप अमरूद का उपयोग कर रहे हैं। या आप धाराओं का उपयोग कर सकते हैं:Map<Integer, MyEnum> reverseLookup = Arrays.stream(MyEnum.values()).collect(Collectors.toMap(MyEnum::getValue, Function.identity()));
shmosel

1
एक getValue()विधि को भी परिभाषित करना चाह सकते हैं ।
shmosel

@shmosel उफ़, मैं getValue फ़ंक्शन को याद किया, धन्यवाद। स्टैकओवरफ्लो में जेनेरिक संस्करणों को टाइप करने से हमेशा पैन नहीं निकलता है। एक लिंक के साथ अमरूद का उपयोग करने के बारे में टिप्पणी जोड़ा। धाराओं के लिए अमरूद विधि को प्राथमिकता दें।
चाड बेफ़ुस

4

आप values()enum से अधिक पुनरावृति कर सकते हैं और enum के पूर्णांक मान की तुलना idनीचे दिए गए तरीके से कर सकते हैं:

public enum  TestEnum {
    None(0),
    Value1(1),
    Value2(2),
    Value3(3),
    Value4(4),
    Value5(5);

    private final int value;
    private TestEnum(int value) {
        this.value = value;
    }

    public int getValue() {
        return value;
    }

    public static TestEnum  getEnum(int value){
        for (TestEnum e:TestEnum.values()) {
            if(e.getValue() == value)
                return e;
        }
        return TestEnum.None;//For values out of enum scope
    }
}

और बस इस तरह का उपयोग करें:
TestEnum x = TestEnum.getEnum(4);//Will return TestEnum.Value4
मुझे आशा है कि यह मदद करता है;)


3

@ChadBefus के उत्तर और @shosel टिप्पणी के आधार पर, मैं इसका उपयोग करने की सलाह दूंगा। (कुशल खोज, और शुद्ध जावा पर काम करता है> = 8)

import java.util.stream.Collectors;
import java.util.function.Function;
import java.util.Map;
import java.util.Arrays;

public enum MyEnum {
    OPTION_1(-66),
    OPTION_2(32);

    private int value;
    private MyEnum(final int value) {
        this.value = value;
    }

    public int getValue() {
        return this.value;
    }

    private static Map<Integer, MyEnum> reverseLookup =
        Arrays.stream(MyEnum.values()).collect(Collectors.toMap(MyEnum::getValue, Function.identity()));

    public static MyEnum fromInt(final int id) {
        return reverseLookup.getOrDefault(id, OPTION_1);
    }
    public static void main(String[] args) {
        System.out.println(fromInt(-66).toString());
    }
}

0

एक अच्छा विकल्प है से बचने से रूपांतरण intकरने के लिए enum() y.ordinal करने के लिए () और बदले एक्स या वाई तदनुसार उदाहरण के लिए, यदि आप अधिक से अधिक मूल्य की जरूरत है, तो आप x.ordinal तुलना कर सकते हैं:। (इस तरह की तुलना को सार्थक बनाने के लिए आपको मूल्यों को फिर से क्रमबद्ध करने की आवश्यकता हो सकती है।)

यदि यह संभव नहीं है, तो मैं MyEnum.values()एक स्थिर सरणी में संग्रहीत करूंगा ।


1
यदि आप DB से int प्राप्त करते हैं और इसे Enum में बदलना चाहते हैं, जो मुझे लगता है कि एक बहुत ही सामान्य कार्य है, तो आपको int -> enum रूपांतरण, IMO .. की आवश्यकता होगी
Yuki Inoue

0

यह डॉक्टरों के रूप में एक ही जवाब है लेकिन यह दर्शाता है कि कैसे उत्परिवर्ती सरणियों के साथ समस्या को खत्म करना है। यदि आप शाखा भविष्यवाणी के कारण इस तरह के दृष्टिकोण का उपयोग पहले करते हैं, तो शून्य प्रभाव बहुत कम होगा और पूरे कोड में केवल एक बार परिवर्तनशील सरणी मान () फ़ंक्शन को कॉल किया जाता है। चूंकि दोनों चर स्थिर हैं, वे इस गणना के प्रत्येक उपयोग के लिए n * मेमोरी का उपभोग नहीं करेंगे।

private static boolean arrayCreated = false;
private static RFMsgType[] ArrayOfValues;

public static RFMsgType GetMsgTypeFromValue(int MessageID) {
    if (arrayCreated == false) {
        ArrayOfValues = RFMsgType.values();
    }

    for (int i = 0; i < ArrayOfValues.length; i++) {
        if (ArrayOfValues[i].MessageIDValue == MessageID) {
            return ArrayOfValues[i];
        }
    }
    return RFMsgType.UNKNOWN;
}

0
enum MyEnum {
    A(0),
    B(1);
    private final int value;
    private MyEnum(int val) {this.value = value;}
    private static final MyEnum[] values = MyEnum.values();//cache for optimization
    public static final getMyEnum(int value) { 
        try {
            return values[value];//OOB might get triggered
        } catch (ArrayOutOfBoundsException e) {
        } finally {
            return myDefaultEnumValue;
        }
    }
}


@ शमोसेल का मानना ​​है कि यदि सीमा से बाहर अपेक्षाकृत बहुत कम हैं, तो अपवाद काफी बेहतर हैं।
Zoso

आपका विश्वास किस पर आधारित है?
shmosel

0

कोटलिन में:

enum class Status(val id: Int) {
    NEW(0), VISIT(1), IN_WORK(2), FINISHED(3), CANCELLED(4), DUMMY(5);

    companion object {
        private val statuses = Status.values().associateBy(Status::id)

        fun getStatus(id: Int): Status? = statuses[id]
    }
}

उपयोग:

val status = Status.getStatus(1)!!

0

इसे लागू किया। यह लापता मूल्यों, नकारात्मक मूल्यों के लिए अनुमति देता है और कोड को सुसंगत रखता है। नक्शा भी कैश किया गया है। एक इंटरफेस का उपयोग करता है और जावा 8 की जरूरत है।

enum

public enum Command implements OrdinalEnum{
    PRINT_FOO(-7),
    PRINT_BAR(6),
    PRINT_BAZ(4);

    private int val;
    private Command(int val){
        this.val = val;
    }

    public int getVal(){
        return val;
    }

    private static Map<Integer, Command> map = OrdinalEnum.getValues(Command.class);
    public static Command from(int i){
        return map.get(i);
    }
}

इंटरफेस

public interface OrdinalEnum{
    public int getVal();

    @SuppressWarnings("unchecked")
    static <E extends Enum<E>> Map<Integer, E> getValues(Class<E> clzz){
        Map<Integer, E> m = new HashMap<>();
        for(Enum<E> e : EnumSet.allOf(clzz))
            m.put(((OrdinalEnum)e).getVal(), (E)e);

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