2013-08-23 13 views
8

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

Foo.VALUE_2.myMethod(); 

कारण है, कि संकलक गणन के अंदर ही है कि विधि के लिए दिखेगा:

enum Foo { 
    VALUE_1 { 
     public int myVariable = 1; 
    }, 
    VALUE_2 { 
     public void myMethod() { 
      // 
     } 
    }, 
    VALUE_3; 
} 

जैसी उम्मीद थी, यह निम्नलिखित तरीके से इस तरह के एक तत्व का उपयोग करना संभव नहीं है ।

मैं माना है कि यह गणन के बाहर से इन तरीकों और चर का उपयोग करने के संभव नहीं है।

enum Foo { 
    VALUE(internalVariable) { 
     int internalVariable = 1; 
    }; 

    private Foo(int param) { 
     // 
    } 
} 

यह संभव नहीं था इस तरह के एक निर्माण को संकलित करने के: इस कारण से, मैं एक पैरामीट्रिक निर्माता बना सकते हैं और कुछ आंतरिक चर से कॉल करने की कोशिश की। अब मैं सोच रहा था कि अगर इसे एक्सेस करने का कोई तरीका नहीं है तो निरंतर अंदर कुछ परिभाषित करने का क्या मतलब है।

मैं बाहर की जाँच करने के लिए अगर यह किसी तरह से टकरा निरंतर में समान नाम वाले तरीकों के साथ-साथ में शुमार ही बनाने के लिए कोशिश कर रहा था। यह नहीं था!

enum Foo { 
    VALUE_1 { 
     int myVariable = 1; 

     public int myMethod() { 
      return myVariable; 
     } 
    }, 
    VALUE_2 { 
     // 
    }; 

    public int myMethod() { 
     return 0; 
    } 
} 

और यहां मजेदार क्षण आता है! मैंने गणना के अंदर myMethod() की कॉल को आगे बढ़ाने की कोशिश की और वास्तव में यह पता लगाया कि यह जावा जादू कैसे काम करता है। विधियों, जिन्हें निरंतर अंदर परिभाषित किया गया है, गणना के भीतर परिभाषित विधियों को ओवरराइड करता है।

Foo.VALUE_1.myMethod(); // Returns 1 
Foo.VALUE_2.myMethod(); // Returns 0 

हालांकि, हम चर को ओवरराइड नहीं कर सकते हैं, है ना? तो मैं उत्सुक था, यह केवल चर के साथ कैसे काम करता है।

enum Foo { 
    VALUE_1 { 
     public int myVariable = 1; 
    }, 
    VALUE_2 { 
     // 
    }; 

    public int myVariable = 0; 
} 

.... 

System.out.println(Foo.VALUE_1.myVariable); // Returns 0 
System.out.println(Foo.VALUE_2.myVariable); // Returns 0 

अब मैं अंत में अपने सवालों के हो रही है:

  1. क्यों अगर मैं इस विधि के बिना निरंतर और बाईं गणन अंदर सार्वजनिक विधि बनाने खाली मैं किसी भी त्रुटि नहीं मिलता है? उस मामले में, विधि मैं सिर्फ बिल्कुल नहीं कहा जा सकता परिभाषित किया। या मैं गलत हूँ?

    अद्यतन: मुझे पता है कि गणना इंटरफ़ेस को कार्यान्वित कर सकती है। हालांकि, अगर मेरे पास नहीं है तो विशेष रूप से कहा गया है कि, संपूर्ण कोड व्यर्थ है।

    किसी ने इंगित किया कि सामान्य तरीके से भाषा से विधि तक पहुंचा नहीं जा सकता है, फिर भी प्रतिबिंब का उपयोग करना संभव है। खैर ... क्यों हम एक दुर्गम कीवर्ड डिजाइन नहीं है?

    inaccessible void magicalMethod() { 
        // 
    } 
    

    ऐसी विधि * .class फ़ाइल में संकलित की जाएगी। जब आप इसका उपयोग करना चाहते हैं, तो आपको अपने द्वारा लोड बाइटकोड करना होगा और इसकी व्याख्या करना होगा।

    मैं बस नहीं समझ सकता, यह क्यों नहीं पहुंचा जा सकता विधि निर्धारित करना संभव है। एकमात्र कारण मुझे लगता है कि प्रोग्रामर काम कर रहा है और अभी तक इंटरफ़ेस की परिभाषा नहीं है।तो वह सिर्फ एकल विधियों का कोड तैयार कर रहा है और बाद में "उपकरण" कीवर्ड जोड़ देगा। के अलावा यह अजीब है, फिर भी सभी स्थिरांक में ऐसी विधि की आवश्यकता होगी।

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

  2. अगर मैं सार्वजनिक चर (या फ़ील्ड, अधिक सटीक होने के लिए) बनाते हैं तो मुझे कोई त्रुटि क्यों नहीं मिलती है? इसे किसी भी मामले (बाहर से) में नहीं पहुंचा जा सकता है। इसलिए, संशोधक "सार्वजनिक" यहां कोई समझ नहीं आता है।

    अद्यतन: यह दृश्यता संशोधक यहां पूरी तरह से बेकार है को छोड़कर, और अधिक कम पिछले बिंदु के रूप में एक ही बात है। यह वास्तव में कोई फर्क नहीं पड़ता कि यह सार्वजनिक है, या निजी संरक्षित है, क्योंकि आप वैसे भी इसे एक्सेस नहीं कर पाएंगे। मुझे लगता है कि यह एक बग है।

  3. ऐसा क्यों है संभव है (दृश्यता बिना संशोधक) एक वर्ग को परिभाषित, लेकिन इंटरफेस नहीं? हाँ, आप शायद इतनी क्रूर गणना नहीं लिखना चाहेंगे कि आपको निरंतर कक्षाओं को परिभाषित करने और यहां तक ​​कि वहां विरासत का उपयोग करने की आवश्यकता होगी। लेकिन यदि कक्षाओं और अमूर्त वर्गों को परिभाषित करना संभव है, तो यह थोड़ा अजीब लगता है।

    अद्यतन: यह निश्चित रूप से कुछ आप नियमित आधार पर आवश्यकता होगी नहीं है, लेकिन मैं है कि यह उपयोगी हो सकता है समझते हैं। लेकिन यह केवल कक्षाओं तक सीमित क्यों है और इंटरफेस भी परिभाषित नहीं किया जा सकता है?

    enum Foo { 
        VALUE { 
         class MyClass { 
          // OK 
         } 
    
         abstract class MyAbstractClass { 
          // OK 
         } 
    
         interface MyInterface { 
          // FAIL. It won't compile. 
         } 
        } 
    } 
    
  4. क्या आपने कहीं ऐसी कार्यक्षमता का उपयोग किया था? मैं कल्पना कर सकता हूं कि यह उपयोगी हो सकता है, लेकिन यह थोड़ा उलझन में है। इसके अलावा, जब मैं इसके बारे में कुछ संसाधन खोज रहा था, मुझे कुछ भी नहीं मिला।

    अद्यतन: मैं कुछ व्यावहारिक उदाहरण एक एनम निरंतर वर्ग निकाय में ओवरराइड विधियों को देखना चाहता हूं। क्या आपने इसे कुछ ओपन-सोर्स प्रोजेक्ट में देखा है?

पर्यावरण:

$ java -version 
java version "1.7.0_21" 
OpenJDK Runtime Environment (IcedTea 2.3.9) (7u21-2.3.9-0ubuntu0.12.10.1) 
OpenJDK 64-Bit Server VM (build 23.7-b01, mixed mode) 

अपने समय के लिए और अपने जवाब के लिए धन्यवाद!

+0

आप निर्माता फैक्ट्रीज ओपन सोर्स प्रोजेक्ट में एनम कॉस्टेंट के अंदर ओवरराइड विधियों का व्यावहारिक उदाहरण पा सकते हैं: http://www.github.com/raspacorp/maker – raspacorp

उत्तर

2

अगर मैं इस विधि के बिना स्थिर और बाएं गणना के अंदर सार्वजनिक विधि बना देता हूं तो मुझे कोई त्रुटि क्यों नहीं मिलती है? उस स्थिति में, जिस विधि को मैंने अभी परिभाषित किया है उसे बिल्कुल नहीं कहा जा सकता है। या मैं गलत हूँ?

वास्तव में संकलक देखने के लिए कि विधि enum निरंतर की क्लास शरीर के बाहर दिखाई नहीं देता है सक्षम होना चाहिए और चेतावनी दी है आप अगर यह नहीं किया जाता है - मुझे यकीन है कि ग्रहण करता है कि के लिए पता है। Dasblinkenlight points out के रूप में, इस तरह की एक सार्वजनिक विधि वास्तव में एक इंटरफेस द्वारा घोषित एक विधि का ओवरराइड हो सकता है जो enum लागू करता है।

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

जैसा कि मैंने पहले ही उल्लेख किया है, यह विशेष रूप से निरंतर कक्षाओं पर लागू नहीं होता है। कई स्कॉप्स हैं - निजी नेस्टेड कक्षाएं, स्थानीय कक्षाएं, अज्ञात वर्ग - जहां सदस्य के लिए यह व्यर्थ है।

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

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

उपरोक्त के समान - संकलक या कम से कम कुछ आईडीई आपको चेतावनी देंगे यदि कोई चर का उपयोग नहीं किया जाता है। यह वही है जैसे आपने को private नेस्टेड क्लास में परिवर्तनीय घोषित किया है और फिर इसे कहीं भी संदर्भित नहीं किया है। किसी भी मामले में, ऐसी परिस्थितियों को रोकने के लिए जेएलएस की प्राथमिकता नहीं है, इसके बावजूद कि प्रतिबिंब की आंख सभी को देखती है।

यह पिछले बिंदु की तरह ही कम है, दृश्यता संशोधक को छोड़कर यहां पूरी तरह से बेकार है। यह वास्तव में कोई फर्क नहीं पड़ता कि यह सार्वजनिक, संरक्षित या निजी है, क्योंकि आप वैसे भी इसका उपयोग नहीं कर पाएंगे। मुझे लगता है कि यह एक बग है।

यहां, आप भूल रहे हैं कि सदस्यों को अभी भी एनम निरंतर वर्ग निकाय के भीतर उपयोग किया जा सकता है - उदाहरण के लिए एक सहायक विधि के बारे में सोचें। यह सिर्फ इतना है कि इस मामले में एक्सेस मॉडिफायर बस कोई फर्क नहीं पड़ता और छोड़ दिया जा सकता है।

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

यह एक अच्छा सवाल है, और मुझे यह समझने में थोड़ी देर लग गई कि आपका क्या मतलब है।स्पष्ट करने के लिए, तुम कह रहे हो कि इस स्थिति में केवल वर्ग की अनुमति है:

VALUE_1 { 
    class Bar { } 
    interface Baz { } 
}, 

इस पर प्रकाश डाला करने के लिए, वर्ग static आज़मा कर देखें:

VALUE_1 { 
    static class Bar { } 
    interface Baz { } 
}, 

अब न तो अनुमति दी जाती है। क्यूं कर? static को कुछ भी निरंतर शरीर में घोषित नहीं किया जा सकता है, क्योंकि शरीर उस स्थिरता के इंस्टेंस के संदर्भ में है।

class Outer { 

    class Inner { 
     // nothing static allowed here either! 
    } 
} 

स्थैतिक चर, विधियों, वर्ग, और इंटरफेस (जो परोक्ष स्थिर हैं जब नेस्ट) ऐसी सभी में मना रहे हैं: यह एक आंतरिक (गैर स्थिर नेस्ट) वर्ग के दायरे में किया जा रहा है के समान है एक गुंजाइश

क्या आपने कहीं ऐसी कार्यक्षमता का उपयोग किया था? मैं कल्पना कर सकता हूं कि यह उपयोगी हो सकता है, लेकिन यह थोड़ा उलझन में है। इसके अलावा, जब मैं इसके बारे में कुछ संसाधन खोज रहा था, मुझे कुछ भी नहीं मिला।

यह स्पष्ट नहीं है कि विशेष रूप से आप किस कार्यक्षमता का जिक्र करते हैं। कृपया यह निर्दिष्ट करने के लिए प्रश्न अपडेट करें कि आप वास्तव में क्या खोज रहे हैं - एक एनम निरंतर वर्ग निकाय में ओवरराइड विधियां? खेत? सहायक तरीके? सहायक वर्ग? कृपया स्पष्ट करें।

+0

उत्तर के लिए धन्यवाद! आप सही हैं, यह वास्तव में चेतावनी का उत्पादन कर रहा है। मैं पूछना चाहता था कि यह त्रुटि क्यों नहीं दे रहा है, लेकिन केवल चेतावनी :-)। जब आप इसे पोस्ट करते थे तो मैं सिर्फ सवाल संपादित कर रहा था। – tzima

+0

@ TomášZíma मैंने आपके अपडेट का जवाब देने के लिए मेरा जवाब अपडेट कर दिया है। –

+0

धन्यवाद! मैंने अपना अंतिम प्रश्न अपडेट कर लिया है। मैं उस बारे में फिर से सोच रहा था और आप शायद सही हैं कि त्रुटि उत्पन्न करना जरूरी नहीं है। लेकिन उदाहरण के लिए इंटरफ़ेस में केवल सार्वजनिक विधि परिभाषित की जा सकती है। अन्य मामले में यह त्रुटि के साथ समाप्त हो जाएगा ("अमान्य संशोधक हटाएं")। यही वह है जो मैं कम से कम क्षेत्र के मामले में उम्मीद कर रहा था (केवल "निजी" अनुमति होगी)। – tzima

2

JLS

से एक enum निरंतर की वैकल्पिक वर्ग शरीर परोक्ष एक गुमनाम वर्ग घोषणा (§15.9.5) है कि तुरंत enclosing enum प्रकार फैली परिभाषित करता है।

जब है वहाँ कोई myMethod() Enum ही (या इसके supertypes) में घोषित इस

VALUE_2 { 
    public void myMethod() { 
     // 
    } 
}, 

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

संपादित

3 प्रश्न के लिए, क्योंकि तुम क्या कर रहे हैं एक गुमनाम वर्ग की घोषणा है, कोई अन्य घटक (लागू करने के लिए) इंटरफेस के लिए उपयोग होगा। दूसरी ओर एक वर्ग व्यवहार प्रदान करता है और इसलिए अज्ञात वर्ग के भीतर उपयोग किया जा सकता है।

बेनामी कक्षाओं पर कुछ restrictions देखें।

समाप्ति संपादित

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

singleton pattern implemented with an enum पर एक नज़र डालें। हो सकता है कि आप अपने सिंगल कार्यान्वयन के साथ कई सिंगलेट्स लेना चाहें। अतिरंजित तरीकों के साथ बेनामी एनम कक्षा घोषणा यह पूरा करने का एक तरीका हो सकता है।

3

[...] जिस विधि को मैंने अभी परिभाषित किया है उसे बिल्कुल नहीं कहा जा सकता है। या मैं गलत हूँ?

सही है, तुम गलत हो: जावा enum रों इस तरह, इंटरफेस को लागू कर सकते हैं:

interface Bar { 
    void myMethod(); 
} 
enum Foo implements Bar { 
    VALUE_1 { 
     public void myMethod() { 
      System.err.println("val1"); 
     } 
    }; 
} 

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

जहां तक ​​सार्वजनिक चर के संबंध हैं, ऐसा लगता है कि प्रतिबिंब यहां एकमात्र तरीका है। फिर भी, इस पर प्रतिबंध लगाने का कोई कारण नहीं है (हालांकि उनके लिए एक उपयोगी अनुप्रयोग की कल्पना करना मुश्किल है)।

क्या आपने कहीं ऐसी कार्यक्षमता का उपयोग किया था?

मैं एक enum कि एक अंतरफलक कार्यान्वित उपयोग करते हैं, प्रत्येक लगातार अपनी विशिष्ट तरीके से इंटरफेस के तरीकों को लागू करने के साथ किया था।

+0

आपके द्वारा उद्धृत किया गया पहला अनुभाग संदर्भित करता है 'enum' के शरीर में घोषित एक सार्वजनिक विधि जहां ओपी _ बाएं गणना इस विधि के बिना खाली है। दूसरे शब्दों में, यह विधि कहीं भी एक इंटरफेस में नहीं है और अज्ञात वर्ग के लिए स्थानीय है। –

+0

@SotiriosDelimanolis नहीं, यह enum के शरीर में नहीं है: विधि व्यक्तिगत मूल्य पर है, वर्ग पर नहीं। इंटरफ़ेस पूरे enum पर लागू होता है, यद्यपि। – dasblinkenlight

+0

मुझे लगता है कि ओपी का अर्थ एनम निरंतर अंदर घोषित एक विधि है, लेकिन कहीं और नहीं, न कि enum स्वयं, कुछ इंटरफ़ेस यह कार्यान्वित नहीं कर रहा है। कहीं भी नहीं। उस स्थिति में प्रतिबिंब के अलावा यह सुलभ नहीं होगा, यह अनाम है। –

4

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

public enum SoundPack { 
    CLASSICAL { 
     @Override 
     public String getSoundPickUp() { 
      return "res/sounds/classical/pick.wav"; 
     } 

     @Override 
     public String getSoundNewLevel() { 
      return "res/sounds/classical/success.wav"; 
     } 

     @Override 
     public String getSoundFail() { 
      return "res/sounds/fail.wav"; 
     } 
    }, 
    UNHEALTHY { 
     @Override 
     public String getSoundPickUp() { 
      return "res/sounds/unhealthy/quick_fart.wav"; 
     } 

     @Override 
     public String getSoundNewLevel() { 
      return "res/sounds/unhealthy/toilet_flush.wav"; 
     } 

     @Override 
     public String getSoundFail() { 
      return "res/sounds/unhealthy/vomiting.wav"; 
     } 
    }; 

    public abstract String getSoundPickUp(); 
    public abstract String getSoundNewLevel(); 
    public abstract String getSoundFail(); 
} 

तो, मैंने अभी ऊपर दिए गए enum को परिभाषित किया है। अगर मैं कुछ ध्वनि चलाने के लिए की जरूरत है, मैं पथ बहुत बस प्राप्त कर सकते हैं, अब

private SoundPack soundPack = SoundPack.CLASSICAL; 

:

configuration.getSoundPack().getSoundNewLevel(); 

विन्यास वर्ग है, जो सभी विन्यास धारण किया जाता है, इस तरह सिर्फ एक विशेषता है फ़ील्ड soundpack को एक और मान असाइन करके बस आसानी से रनटाइम बदला जा सकता है। अगर ध्वनि अभी तक लोड नहीं हुआ है (और मौका है कि वे ऐसा नहीं होंगे क्योंकि मैं आलसी लोडिंग का उपयोग कर रहा हूं), परिवर्तन तुरंत प्रभावित होंगे। कुछ और बदलने के बिना।

इसके अलावा, अगर मैं नया ध्वनि पैक जोड़ना चाहता हूं, तो यह उस enum में नए स्थिरता को परिभाषित करके किया जाएगा। ग्रहण चेतावनी दिखाएगा, मैं केवल CTRL + 1 दबा दूंगा और इन विधियों को उत्पन्न करूंगा। तो यह भी बहुत आसान है।

मुझे पता है कि यह ऐसा करने का सबसे अच्छा तरीका नहीं है। लेकिन यह आसान है, यह तेज़ है और सबसे महत्वपूर्ण क्या है: मैं को प्रैक्सिस में उपयोग करने के लिए प्रयास करना चाहता था। :-)

संबंधित मुद्दे