2009-07-22 3 views
59

जावा में, आप एक enum इस प्रकार बना सकते हैं:जावा 6 enums के लिए मूल्य() लागू किया गया है?

public enum Letter { 
    A, B, C, D, E, F, G; 

    static { 
     for(Letter letter : values()) { 
      // do something with letter 
     } 
    } 
} 

यह सवाल विधि से संबंधित है "() मूल्यों"। विशेष रूप से, यह कैसे कार्यान्वित किया जाता है? आम तौर पर, मैं एफ 3 या CTRL + का उपयोग कर जावा कक्षाओं के लिए स्रोत पर कूद सकता हूं (ग्रहण में भी क्लिक करें (यहां तक ​​कि स्ट्रिंग, कैरेक्टर, इंटीजर और यहां तक ​​कि एनम जैसे वर्गों के लिए)। अन्य enum विधियों के स्रोत को देखना संभव है (उदा।, ValueOf (स्ट्रिंग))।

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

क्या इसके लिए कोड मूल है? या क्या JVM/compiler विशेष रूप से इसका इलाज करता है, केवल मूल्यों से एक नया उदाहरण लौटाता है() जब यह साबित नहीं कर सकता कि इसे संशोधित नहीं किया जाएगा।

उत्तर

96

असल में, कंपाइलर (जावा) आपके enum को एक स्थिर सरणी में अनुवाद करता है जिसमें संकलन समय पर आपके सभी मान होते हैं। जब आप मान() कहते हैं, तो यह आपको इस सरणी की .clone'd() प्रतिलिपि देता है।

इस सरल enum को देखते हुए:

public enum Stuff { 
    COW, POTATO, MOUSE; 
} 

आप वास्तव में कोड है कि जावा उत्पन्न करता है देख सकते हैं:

public enum Stuff extends Enum<Stuff> { 
    /*public static final*/ COW /* = new Stuff("COW", 0) */, 
    /*public static final*/ POTATO /* = new Stuff("POTATO", 1) */, 
    /*public static final*/ MOUSE /* = new Stuff("MOUSE", 2) */; 
    /*synthetic*/ private static final Stuff[] $VALUES = new Stuff[]{Stuff.COW, Stuff.POTATO, Stuff.MOUSE}; 

    public static Stuff[] values() { 
     return (Stuff[])$VALUES.clone(); 
    } 

    public static Stuff valueOf(String name) { 
     return (Stuff)Enum.valueOf(Stuff.class, name); 
    } 

    private Stuff(/*synthetic*/ String $enum$name, /*synthetic*/ int $enum$ordinal) { 
     super($enum$name, $enum$ordinal); 
    } 
} 

आप कैसे javac एक अस्थायी निर्देशिका बनाकर अपनी कक्षाओं 'तब्दील हो' देख सकते हैं और चल रहा है:

javac -d <output directory> -XD-printflat filename.java 
+1

कोई सिस्टम नहीं होगा। रैरेकॉपी तेजी से हो? – Gandalf

+0

+1; अतिरिक्त कुडोस यदि आप 'सिंथेटिक' के अर्थ की व्याख्या करेंगे। – wchargin

+3

'मान()' विधि 'क्लोन()' सरणी '$ VALUES' क्यों है? क्यों न सिर्फ इसे वापस लौटें? – RestInPeace

2

यदि आप इसे स्थानीय चर में निर्दिष्ट करते हैं तो केवल एक चीज जिसे आप संशोधित कर सकते हैं वह इस चर के लिए एक और enum असाइन कर रहा है। यह enum खुद को नहीं बदलेगा क्योंकि आप केवल अपने चर संदर्भों को बदल रहे हैं।

ऐसा लगता है कि enums वास्तव में सिंगलेट्स हैं ताकि आपके पूरे कार्यक्रम में प्रत्येक enum से केवल एक तत्व मौजूद हो, यह == ऑपरेटर enums के लिए कानूनी बनाता है।

इसलिए कोई प्रदर्शन समस्या नहीं है और आप गलती से अपनी enum परिभाषा में कुछ बदल नहीं सकते हैं।

+2

मुझे लगता है कि ओपी का मतलब मूल्यों() द्वारा लौटाए गए सरणी को संशोधित करना है। यदि यह एक ही सरणी वस्तु है जिसे आंतरिक रूप से रखा जाता है (एक प्रतिलिपि के बजाय), फिर इसे संशोधित करना (उदाहरण के लिए एक तत्व को दूसरे तत्व को असाइन करना, तत्व को शून्य देना आदि) गड़बड़ कर देगा, न केवल enum class के लिए, लेकिन किसी भी भविष्य के मूल्यों के लिए कॉल() – newacct

+1

हाँ आप सही हैं। यदि कोई क्लोन नहीं था तो आप सरणी से एनम को हटा सकते हैं और बाद में मूल्यों से कॉल इस मान को याद करेंगे। – Janusz

+0

और फिर भी यह सिर्फ एक उथली प्रतिलिपि है, क्योंकि enum उदाहरण अद्वितीय हैं। –

1

क्या इसके लिए कोड मूल है? या क्या JVM/compiler विशेष रूप से इसका इलाज करता है, केवल मूल्यों से एक नया उदाहरण लौटाता है() जब यह साबित नहीं कर सकता कि इसे संशोधित नहीं किया जाएगा।

1) संख्या या कम से कम वर्तमान कार्यान्वयन में नहीं। साक्ष्य के लिए @ लुकास्मो का जवाब देखें।

2) AFAIK, नहीं।

हाइपोटेटिक रूप से यह ऐसा कर सकता है। हालांकि, यह साबित करना कि स्थानीय रूप से एक सरणी कभी भी संशोधित नहीं होती है, जेआईटी के प्रदर्शन के लिए जटिल और अपेक्षाकृत महंगा होगी। यदि values() नामक विधि से सरणी "बच जाती है", तो यह अधिक जटिल & अधिक महंगा हो जाता है।

संभावना है कि यह (काल्पनिक) अनुकूलन भुगतान नहीं करेगा ... जब सभी जावा कोड पर औसत होता है।

दूसरा मुद्दा यह है कि यह (काल्पनिक) अनुकूलन सुरक्षा छेद खोल सकता है।


दिलचस्प बात यह है कि JLS कि values() सदस्य एक सरणी प्रतिलिपि रिटर्न निर्दिष्ट करने के लिए प्रतीत नहीं होता है। सामान्य ज्ञान कहता है कि यह करना चाहिए ... लेकिन यह वास्तव में निर्दिष्ट नहीं है।

1 - यह एक भारी सुरक्षा छेद यदि values()enum मूल्यों का एक साझा (परिवर्तनशील) सरणी लौटे होगा।