2013-06-06 11 views
10

मैं जावा 1.6 पर अपने कॉलेज पाठ्यक्रम में एक एलएएलजी कंपाइलर विकसित कर रहा हूं। तो मैंने एक प्रकार की कक्षा और व्याकरण वर्ग किया।Enum का Enum NULL

EnumTypes

public enum EnumTypes { 

    A("OLA"), 
    B("MUNDO"), 
    C("HELLO"), 
    D("WORLD"), 

    /** 
    * The order below is reversed on purpose. 
    * Revert it and will you get a NULL list of types furder. 
    */ 

    I(EnumGrammar.THREE), 
    H(EnumGrammar.TWO), 
    F(EnumGrammar.ONE), 
    E(EnumGrammar.ZERO); 

    private String strValue; 
    private EnumGrammar enumGrammarValue; 

    private EnumTypes(String strValue) { 
     this.strValue = strValue; 
    } 

    private EnumTypes(EnumGrammar enumGrammarValue) { 
     this.enumGrammarValue = enumGrammarValue; 
    } 

    public String getStrValue() { 
     return strValue; 
    } 

    public EnumGrammar getEnumTiposValue() { 
     return enumGrammarValue; 
    } 
} 

EnumGrammar

public enum EnumGrammar { 

    ZERO(EnumTypes.A,EnumTypes.B,EnumTypes.F,EnumTypes.D), 
    ONE(EnumTypes.C), 
    TWO(EnumTypes.B,EnumTypes.H), 
    THREE(EnumTypes.D,EnumTypes.A,EnumTypes.C); 

    private EnumTypes[] values; 

    private EnumGrammar(EnumTypes ... values) { 
     this.values = values; 
    } 

    public EnumTypes[] getValues() { 
     return values; 
    } 
} 

जब मैं फोन EnumTypes.E.getEnumTiposValue().getValues() जहां EnumTypes.F मूल्य होने की अपेक्षा की जाती है शून्य है।

मुख्य

public class Main { 

    public static void main(String[] args) { 
     //prints [A, B, null, D] 
     System.out.println(Arrays.toString(EnumTypes.E.getEnumTiposValue().getValues())); 
    } 

} 

एक समाधान या ऐसा ही कुछ कर रहे हैं?

धन्यवाद!

+0

+1 और प्रजनन यहाँ है: http://ideone.com/O9bZx3 –

+4

से संबंधित एक सर्कुलर निर्भरता पहेली की तरह लग रहा एक दूसरे के संदर्भ में दो enum वर्ग 'स्थिरांक की स्थिर init। –

+0

यह कभी-कभी सर्कुलर निर्भरता कणिका के बावजूद हो सकता है यदि आपका आलसी कुछ अजीब वर्ग लोडर लोड कर रहा हो। –

उत्तर

11

अनिवार्य रूप से, कक्षा पूरी तरह से निर्मित होने से पहले कक्षा के बाहर जाने के लिए किसी ऑब्जेक्ट के संदर्भ को अनुमति देने के लिए यह हमेशा एक बहुत ही जोखिम भरा बात है, जो कि कन्स्ट्रक्टर समाप्त होने से पहले है। Enums सिंगलेट हैं। यहां आपके पास दो वर्ग हैं जिनके रचनाकार एक दूसरे के उदाहरणों को एक परिपत्र निर्भरता में प्राप्त करते हैं। इसमें जोड़ें कि वर्ग लोडिंग आलसी है, इसलिए कक्षाएं लोड की जाएंगी और आपके द्वारा चलाए जाने वाले enum उदाहरण बनाए जाएंगे और यह काफी उचित लगता है कि अंतिम परिणाम उस क्रम पर निर्भर करता है जिसमें enums प्रारंभ होते हैं।

मैं अभी जेएलएस से इसी बिंदु को उद्धृत नहीं कर सकता (मैं इसे देख लूंगा), लेकिन मेरा मानना ​​है कि यदि आप किसी ऑब्जेक्ट के संदर्भ को कन्स्ट्रक्टर के बाहर से "कक्षा छोड़ने" की अनुमति देते हैं (जो JVM द्वारा प्रारंभ किए गए सिंगलटन होने के कारण यहां होता है), JVM कुछ अजीब करने के लिए स्वतंत्र है।

संपादित: JLS से इन बातों मामले के लिए महत्वपूर्ण हैं:

  • 17.5.2 - A read of a final field of an object within the thread that constructs that object is ordered with respect to the initialization of that field within the constructor by the usual happens-before rules. If the read occurs after the field is set in the constructor, it sees the value the final field is assigned, otherwise it sees the default value. के बाद से enum मूल्यों आंतरिक रूप से स्थिर अंतिम क्षेत्रों (नीचे 16.5 देखें) की तरह व्यवहार कर रहे हैं, एक enum अगर आप संदर्भ एक और enum के निर्माता के अंदर से जिसका कन्स्ट्रक्टर पहले संदर्भित करता है, कम से कम इन दो वस्तुओं में से एक को पूरी तरह से प्रारंभ नहीं किया जाएगा और इसलिए इस बिंदु पर संदर्भ अभी भी शून्य हो सकता है।
  • 16.5 - The definite assignment/unassignment status of any construct within the class body of an enum constant is governed by the usual rules for classes
  • 8.3.2 - क्षेत्रों
  • 12.4.1 के प्रारंभ के लिए नियम - जब प्रारंभ होता है
+0

आईआईआरसी यदि आप जावा 7 मल्टीथ्रेडेड क्लास लोडर का उपयोग करते हैं तो यह और भी खराब हो जाता है: http://docs.oracle.com/javase/7/docs/technotes/guides/lang/cl-mt.html। –

6

यहाँ है क्या हो रहा है, क्रम में:

  1. आपका कोड कॉल EnumTypes.E.getEnumTiposValue(), ट्रिगर EnumTypes की कक्षा लोडिंग।
  2. EnumTypes की स्थिर प्रारंभिक शुरुआत - इसकी enum स्थिरांक को घोषित किए जाने वाले क्रम में प्रारंभ किया जाएगा।
  3. EnumTypes.AEnumTypes.D के माध्यम से शुरू किया गया है।
  4. EnumTypes.I आरंभिक प्रारंभ होता है - इसके कन्स्ट्रक्टर कॉल संदर्भ EnumGrammar.THREE, EnumGrammar की कक्षा लोडिंग को ट्रिगर करते हुए।
  5. EnumGrammar की स्थिर प्रारंभिक शुरुआत - इसकी enum स्थिरांक को घोषित किए जाने वाले क्रम में प्रारंभ किया जाएगा।
  6. EnumGrammar.ZERO प्रारंभ किया गया है - इसके कन्स्ट्रक्टर कॉल संदर्भ EnumTypes.A, EnumTypes.B, EnumTypes.F, और EnumTypes.D। उनमें से, EnumTypes.Fअभी तक प्रारंभ नहीं किया गया है। इसलिए, इसका संदर्भ null है।

वहाँ से, दो enum वर्गों के स्थिर प्रारंभ खत्म, लेकिन यह EnumGrammar.ZERO के लिए कोई फर्क नहीं पड़ता - अपने values क्षेत्र पहले से ही स्थापित किया गया है।

0

कामकाज के लिए, मान लीजिए कि आपके पास एनुमा और एन्यूएमबी है, मैं सिर्फ एनुमा के कन्स्ट्रक्टर में एनयूएमबी का नाम रखूंगा।

आप Enuma से EnumB पुनः प्राप्त करने के है, तो आप बस का उपयोग कर सकते EnumB.valueOf (EnumA.this.enumB)

उदाहरण के लिए, प्रश्न EnumB

public enum Question { 
RICH_ENOUGH(R.string.question_rich_enough, Arrays.asList(Answer.RICH_ENOUGH_YES, Answer.RICH_ENOUGH_NO)), 
ARE_YOU_SURE(R.string.question_are_you_sure, Arrays.asList(Answer.ARE_YOU_SURE_YES, Answer.ARE_YOU_SURE_NO)), 
FOUND_A_NEW_JOB(R.string.question_found_new_job, Arrays.asList(Answer.FOUND_A_NEW_JOB_YES, Answer.FOUND_A_NEW_JOB_NO)), 
// ... 

है और उत्तर Enuma है

public enum Answer { 
    RICH_ENOUGH_YES(R.string.answer_yes, "ARE_YOU_SURE"), 
    RICH_ENOUGH_NO(R.string.answer_no, "THAT_SOMEBODY"), 
    ARE_YOU_SURE_YES(R.string.answer_yes, null), 
    ARE_YOU_SURE_NO(R.string.answer_no, "FOUND_A_NEW_JOB"), 
    FOUND_A_NEW_JOB_YES(R.string.answer_yes, "GO_FOR_NEW_JOB"), 
    // ... 

    private final int answerStringRes; 
    // Circular reference makes nulls 
    private final String nextQuestionName; 

    Answer(@StringRes int answerStringRes, String nexQuestionName) { 
     this.answerStringRes = answerStringRes; 
     this.nextQuestionName = nexQuestionName; 
    } 

जब भी मैं एक जवाब से अगले प्रश्न प्राप्त करने की आवश्यकता

public Question getNextQuestion() { 
    if (nextQuestionName == null) { 
     return null; 
    } 
    return Question.valueOf(nextQuestionName); 
} 

यह एक कामकाज के लिए काफी आसान होना चाहिए।

उदाहरण स्रोत: मैं बस कल रात लिखा मनोरंजन के लिए एक खुला स्रोत Android एप्लिकेशन - Should I Resign?