2009-03-04 24 views
242

में कनवर्ट करें I enum प्रकार ReportTypeEnum है जो मेरे सभी वर्गों में विधियों के बीच पारित हो जाता है लेकिन मुझे इसे URL पर पास करने की आवश्यकता है, इसलिए मैं int मान प्राप्त करने के लिए सामान्य विधि का उपयोग करता हूं। मेरे अन्य जेएसपी पेज में इसे प्राप्त करने के बाद, मुझे इसे ReportTypeEnum पर वापस बदलने की आवश्यकता है ताकि मैं इसे पास करना जारी रख सकूं।enum ordinal से enum टाइप

मैं औपचारिक को ReportTypeEnum में कैसे परिवर्तित कर सकता हूं?

जावा 6 एसई का उपयोग करना।

+1

अब तक कोई जावा 6 ईई नहीं है (AFAIK)। जावा एसई 6 है, और जावा ईई 5. –

+0

मेरा मतलब जावा एसई 6. – Lennie

उत्तर

504

अपने enum represantation में एक क्रमसूचक परिवर्तित करने के लिए यदि आप ऐसा करना चाहते हो सकता है:

ReportTypeEnum value = ReportTypeEnum.values()[ordinal]; 

सरणी सीमा नोटिस करें।

ध्यान दें कि values() पर प्रत्येक कॉल एक नया क्लोन सरणी देता है जो नकारात्मक तरीके से प्रदर्शन को प्रभावित कर सकता है। यदि आप अक्सर कहलाए जा रहे हैं तो आप सरणी को कैश करना चाहेंगे।

Code example on how to cache values()


इस उत्तर प्रतिक्रिया टिप्पणी

+140

ध्यान दें कि मानों के लिए प्रत्येक कॉल() एक नया क्लोन सरणी देता है, इसलिए यदि आप इसे गंभीर में बुलाएंगे तो आप सरणी को कैश करना चाहेंगे कोड का क्षेत्र – mattbh

+5

उदा। http://stackoverflow.com/a/19277247 – QED

+0

मैंने इस समाधान को लागू किया और यह मेरे लिए काम नहीं कर रहा है। यह लौटाता है कि क्रमिक मान उस क्रम से मेल खाने की गारंटी नहीं है जिसमें गणना किए गए प्रकार जोड़े गए हैं। मुझे नहीं पता कि यह जवाब वकालत कर रहा है, लेकिन मैं लोगों को चेतावनी देना चाहता था फिर भी – IcedDante

128

यह अंदर दी शामिल करने के लिए संपादित किया गया था लगभग निश्चित रूप से एक बुरा विचार है। निश्चित रूप से यदि ordinal de-facto जारी है (उदा। क्योंकि किसी ने URL को बुकमार्क किया है) - इसका मतलब है कि आपको हमेशा भविष्य में enum ऑर्डरिंग को सुरक्षित रखना होगा, जो लाइन के नीचे कोड रखरखाव के लिए स्पष्ट नहीं हो सकता है।

बजाय क्यों एन्कोड नहीं enum का उपयोग कर myEnumValue.name() (और ReportTypeEnum.valueOf(s) के माध्यम से डिकोड)?

+3

बहुत बेहतर विचार –

+0

मैं सहमत हूं, यह बेहतर समाधान है। –

+16

क्या होगा यदि आप enum का नाम बदलते हैं (लेकिन ऑर्डरिंग रखें)? –

6

आप एक स्थिर लुकअप तालिका इस्तेमाल कर सकते हैं:

public enum Suit { 
    spades, hearts, diamonds, clubs; 

    private static final Map<Integer, Suit> lookup = new HashMap<Integer, Suit>(); 

    static{ 
    int ordinal = 0; 
    for (Suit suit : EnumSet.allOf(Suit.class)) { 
     lookup.put(ordinal, suit); 
     ordinal+= 1; 
    } 
    } 

    public Suit fromOrdinal(int ordinal) { 
    return lookup.get(ordinal); 
    } 
} 
+3

यह भी देखें [एनम्स] (http://download.oracle.com/javase/1.5.0/docs/guide/language/enums.html)। – trashgod

+9

वाह! बस वाह! यह निश्चित रूप से साफ है, लेकिन ... आप जानते हैं - मेरे अंदर सी प्रोग्रामर दर्द में चिल्लाता है कि आप एक पूर्ण उड़ा हुआ हैश मैप आवंटित करते हैं और इसके अंदर लुकअप करते हैं, बस अनिवार्य रूप से 4 स्थिरांक प्रबंधित करने के लिए: हुकुम, दिल, हीरे और क्लब! ए सी प्रोग्रामर प्रत्येक के लिए 1 बाइट आवंटित करेगा: 'const char CLUBS = 0;' इत्यादि ... हां, एक हैश मैप लुकअप ओ (1) है, लेकिन हैश मैप की मेमोरी और सीपीयू ओवरहेड, इस मामले में इसे तीव्रता के धीमे और संसाधनों को कॉल करने से भूख लगी है .values ​​() सीधे! कोई आश्चर्य नहीं कि जावा इस तरह के मेमोरी हॉग हैं अगर लोग इस तरह लिखते हैं ... – Leszek

+2

प्रत्येक कार्यक्रम को ट्रिपल ए गेम के प्रदर्शन की आवश्यकता नहीं होती है। कई मामलों में टाइपिंग सुरक्षा, पठनीयता, रखरखाव, क्रॉस प्लेटफार्म समर्थन, कचरा संग्रह, इत्यादि के लिए व्यापार मेमोरी और सीपीयू ... उचित है। एक कारण के लिए उच्च स्तर की भाषाएं मौजूद हैं। – Jan

-2

हर enum नाम() है, जो enum सदस्य के नाम के साथ एक स्ट्रिंग देता है।

enum Suit{Heart, Spade, Club, Diamond}, Suit.Heart.name()Heart प्रदान करेगा।

Enum.valueOf(Suit.class, "Heart") रिटर्न Suit.Heart:

हर enum एक valueOf() विधि है, जो रिवर्स कार्रवाई करने के लिए एक enum प्रकार और एक स्ट्रिंग लेता है, है।

कोई भी नियमों का उपयोग क्यों करेगा मेरे बाहर है। यह नैनोसेकंड तेजी से हो सकता है, लेकिन यह सुरक्षित नहीं है, अगर enum सदस्य बदलते हैं, क्योंकि एक अन्य डेवलपर को पता नहीं हो सकता है कि कुछ कोड औपचारिक मूल्यों पर निर्भर है (विशेष रूप से प्रश्न में उल्लिखित जेएसपी पृष्ठ में, नेटवर्क और डेटाबेस ओवरहेड पूरी तरह से हावी है समय, एक स्ट्रिंग पर एक पूर्णांक का उपयोग नहीं कर रहा है)।

+2

क्योंकि पूर्णांक की तुलना स्ट्रिंग की तुलना में बहुत तेज है? – HighCommander4

+2

लेकिन अगर कोई enum संशोधित करता है (मेमर्स जोड़ता/पुन: व्यवस्थित करता है) तो ordinals बदल जाएगा। कभी-कभी यह सुरक्षा और गति के बारे में नहीं है, खासकर एक जेएसपी पृष्ठ पर जहां नेटवर्क विलंबता पूर्णांक (एक स्ट्रिंग) और एक पूर्णांक की सरणी की तुलना में 1,000,000 गुना अंतर है। –

+0

टूस्ट्रिंग को ओवरराइड किया जा सकता है, इसलिए यह enum नाम वापस नहीं कर सकता है। विधि नाम() है जो enum नाम देता है (यह अंतिम है) – gerardw

74

मैं values() एक बहुत का उपयोग किया जा रहा हूँ, तो:

enum Suit { 
    Hearts, Diamonds, Spades, Clubs; 
    public static final Suit values[] = values(); 
} 

इस बीच जहां कहीं।जावा:

Suit suit = Suit.values[ordinal]; 

अपनी सरणी सीमाओं को ध्यान में रखें।

+2

+1 यह अब तक का सबसे अच्छा समाधान IMHO है क्योंकि कोई विशेष रूप से android.os.Message में ऑर्डिनल पास कर सकता है। – likejiujitsu

+0

यह बहुत चिंताजनक है क्योंकि ** सरणी mutable ** हैं। भले ही मूल्य [] अंतिम है, यह 'Suit.values ​​[0] = Suit.Diamonds; 'को आपके कोड में कहीं भी नहीं रोकता है। आदर्श रूप से ऐसा कभी नहीं होगा, लेकिन * का समग्र सिद्धांत * उत्परिवर्तनीय क्षेत्रों का खुलासा नहीं करता है * अभी भी है। इस दृष्टिकोण के लिए, 'संग्रह .unmodifiableList' या इसके बजाए पसंद करें। – Mshnik

5

मैं ज्यादातर लोगों से सहमत हूं कि ordinal का उपयोग करना शायद एक बुरा विचार है। मैं आमतौर पर इस समस्या को एक निजी कन्स्ट्रक्टर प्रदान करके हल करता हूं जो उदाहरण के लिए एक डीबी मान ले सकता है, फिर जनवरी के उत्तर में एक स्थिर fromDbValue फ़ंक्शन बना सकता है।

public ReportTypeEnum { 
    R1(1), 
    R2(2), 
    R3(3), 
    R4(4), 
    R5(5), 
    R6(6), 
    R7(7), 
    R8(8); 

    private static Logger log = LoggerFactory.getLogger(ReportEnumType.class); 
    private static Map<Integer, ReportTypeEnum> lookup; 
    private Integer dbValue; 

    private ReportTypeEnum(Integer dbValue) { 
     this.dbValue = dbValue; 
    } 


    static { 
     try { 
      ReportTypeEnum[] vals = ReportTypeEnum.values(); 
      lookup = new HashMap<Integer, ReportTypeEnum>(vals.length); 

      for (ReportTypeEnum rpt: vals) 
       lookup.put(rpt.getDbValue(), rpt); 
     } 
     catch (Exception e) { 
      // Careful, if any exception is thrown out of a static block, the class 
      // won't be initialized 
      log.error("Unexpected exception initializing " + ReportTypeEnum.class, e); 
     } 
    } 

    public static ReportTypeEnum fromDbValue(Integer dbValue) { 
     return lookup.get(dbValue); 
    } 

    public Integer getDbValue() { 
     return this.dbValue; 
    } 

} 

अब आप देखने बदल रहा है और इसके विपरीत बिना क्रम बदल सकते हैं।

4

यही वह है जो मैं उपयोग करता हूं। मैं कोई झगड़ा नहीं करता कि यह ऊपर के सरल समाधानों की तुलना में बहुत कम "कुशल" है। यह क्या करता है जब उपरोक्त समाधान में अमान्य ordinal value का उपयोग किया जाता है, तो "ArrayIndexOutOfBounds" से अधिक स्पष्ट अपवाद संदेश प्रदान करता है।

यह इस तथ्य का उपयोग करता है कि EnumSet javadoc इटरेटर रिटर्न तत्वों को उनके प्राकृतिक क्रम में निर्दिष्ट करता है। अगर यह सही नहीं है तो एक जोर है।

जुनीट 4 टेस्ट दर्शाता है कि इसका उपयोग कैसे किया जाता है।

/** 
* convert ordinal to Enum 
* @param clzz may not be null 
* @param ordinal 
* @return e with e.ordinal() == ordinal 
* @throws IllegalArgumentException if ordinal out of range 
*/ 
public static <E extends Enum<E> > E lookupEnum(Class<E> clzz, int ordinal) { 
    EnumSet<E> set = EnumSet.allOf(clzz); 
    if (ordinal < set.size()) { 
     Iterator<E> iter = set.iterator(); 
     for (int i = 0; i < ordinal; i++) { 
      iter.next(); 
     } 
     E rval = iter.next(); 
     assert(rval.ordinal() == ordinal); 
     return rval; 
    } 
    throw new IllegalArgumentException("Invalid value " + ordinal + " for " + clzz.getName() + ", must be < " + set.size()); 
} 

@Test 
public void lookupTest() { 
    java.util.concurrent.TimeUnit tu = lookupEnum(TimeUnit.class, 3); 
    System.out.println(tu); 
} 
0
public enum Suit implements java.io.Serializable, Comparable<Suit>{ 
    spades, hearts, diamonds, clubs; 
    private static final Suit [] lookup = Suit.values(); 
    public Suit fromOrdinal(int ordinal) { 
    if(ordinal< 1 || ordinal> 3) return null; 
    return lookup[value-1]; 
    } 
} 

परीक्षण वर्ग

public class MainTest { 
    public static void main(String[] args) { 
     Suit d3 = Suit.diamonds; 
     Suit d3Test = Suit.fromOrdinal(2); 
     if(d3.equals(d3Test)){ 
      System.out.println("Susses"); 
     }else System.out.println("Fails"); 
    } 
} 

मुझे खुशी है कि आप हमारे साथ साझा करता है, तो आप एक अधिक कुशल कोड है, मेरे enum समय की विशाल और लगातार कहा जाता है हजारों है।

0

मान लीजिए आप निम्नलिखित enum है:

public enum ErrorCodes { 
    BUSINESS_ERROR(100), SERVER_ERROR(500), NETWORK_ERROR(1000); 
} 

डिफ़ॉल्ट रूप से, आप नहीं इसकी संख्यात्मक मान द्वारा एक त्रुटि उदाहरण पुनः प्राप्त कर के बाद से जावा पुनः प्राप्त करने के लिए किसी भी तरह प्रदान नहीं करता होगा एक क्षेत्र द्वारा Enum उदाहरण।

ऐसा करने में, मैं सामान्य रूप से Enum वर्ग के भीतर एक स्थिर hashmap जो निम्नलिखित के रूप में उसके संगत Enum उदाहरण के लिए प्रत्येक मान नक्शे का पर्दाफाश:

public enum ErrorCodes { 
    BUSINESS_ERROR(100), SERVER_ERROR(500), NETWORK_ERROR(1000); 

    private int errorCode; 
    private static Map<Integer, ErrorCodes> errorCodeByErrorNumber = new HashMap<Integer, ErrorCodes>(); 

    static { 
     for (ErrorCodes errorCode : ErrorCodes.values()) { 
      errorCodeByErrorNumber.put(errorCode.getErrorCode(), errorCode); 
     } 
    } 

    private ErrorCodes(int errorCode) { 
     this.errorCode = errorCode; 
    } 

    public int getErrorCode() { 
     return errorCode; 
    } 

    public static ErrorCodes getErrorCodeByNumber(Integer errorNumber) { 
     return errorCodeByErrorNumber.get(errorNumber); 
    } 
} 

अधिक आम Enum संचालन के लिए, इस जाँच: How to use Enums in java