java अज्ञात वर्ग में केवल अंतिम चर उपलब्ध क्यों हैं?




event-handling anonymous-class (9)

  1. केवल यहां अंतिम हो सकता है। क्यूं कर? मैं इसे निजी सदस्य के रूप में रखने के बिना onClick() विधि में पुन: असाइन कैसे कर सकता हूं?

    private void f(Button b, final int a){
        b.addClickHandler(new ClickHandler() {
    
            @Override
            public void onClick(ClickEvent event) {
                int b = a*5;
    
            }
        });
    }
    
  2. जब मैं क्लिक करता हूं तो मैं 5 * a को कैसे वापस कर सकता हूं? मेरा मतलब,

    private void f(Button b, final int a){
        b.addClickHandler(new ClickHandler() {
    
            @Override
            public void onClick(ClickEvent event) {
                 int b = a*5;
                 return b; // but return type is void 
            }
        });
    }
    

लौटा मूल्य प्राप्त करने के लिए आप कक्षा स्तर चर बना सकते हैं। मेरा मतलब

class A {
    int k = 0;
    private void f(Button b, int a){
        b.addClickHandler(new ClickHandler() {
        @Override
        public void onClick(ClickEvent event) {
            k = a * 5;
        }
    });
}

अब आप के के मूल्य प्राप्त कर सकते हैं और जहां आप चाहें इसका उपयोग कर सकते हैं।

आपका उत्तर क्यों है:

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

चूंकि स्थानीय आंतरिक वर्ग न तो वर्ग या पैकेज का सदस्य होता है, इसलिए इसे पहुंच स्तर के साथ घोषित नहीं किया जाता है। (हालांकि, स्पष्ट रहें कि अपने सदस्यों के पास सामान्य वर्ग की तरह पहुंच स्तर हैं।)


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


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

उपयोग के मामले पर विचार करें जहां आवेदन करने की बजाय आपके लैम्ब्डा, किसी स्थान पर संग्रहीत हैं और बाद में चलाए जाते हैं।

मुझे याद है कि जब आप इस तरह के संशोधन करते हैं तो आपको स्मॉलटाक में एक अवैध स्टोर मिल जाएगा।


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


एक चाल है जो अज्ञात वर्ग को बाहरी दायरे में डेटा अपडेट करने की अनुमति देती है।

private void f(Button b, final int a) {
    final int[] res = new int[1];
    b.addClickHandler(new ClickHandler() {
        @Override
        public void onClick(ClickEvent event) {
            res[0] = a * 5;
        }
    });

    // But at this point handler is most likely not executed yet!
    // How should we now res[0] is ready?
}

हालांकि, यह चाल सिंक्रनाइज़ेशन समस्याओं के कारण बहुत अच्छी नहीं है। यदि हैंडलर को बाद में बुलाया जाता है, तो आपको 1) की आवश्यकता होती है यदि हैंडलर को विभिन्न थ्रेड से बुलाया गया हो तो res को एक्सेस सिंक्रनाइज़ करें 2) किसी प्रकार का ध्वज या संकेत होना चाहिए जिसे Res

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

// ...

final int[] res = new int[1];
Runnable r = new Runnable() { public void run() { res[0] = 123; } };
r.run();
System.out.println(res[0]);

// ...

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

( http://en.wikipedia.org/wiki/Final_%28Java%29 )


जैसा कि टिप्पणियों में उल्लेख किया गया है, इनमें से कुछ जावा 8 में अप्रासंगिक हो जाता है, जहां final निहित हो सकता है। यद्यपि एक अज्ञात आंतरिक वर्ग या लैम्ब्डा अभिव्यक्ति में केवल एक प्रभावी रूप से अंतिम चर का उपयोग किया जा सकता है।

यह मूल रूप से जावा closures के तरीके के कारण है।

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

चूंकि मूल्य को गुमनाम आंतरिक वर्ग के उदाहरण में कॉपी किया गया है, तो यह अजीब लगेगा कि चर के बाकी तरीके से परिवर्तनीय संशोधित किया जा सकता है - आपके पास कोड हो सकता है जो एक पुराने चर के साथ काम कर रहा है ( क्योंकि यह प्रभावी रूप से हो रहा है ... आप एक अलग समय पर ली गई प्रतिलिपि के साथ काम करेंगे)। इसी प्रकार यदि आप गुमनाम आंतरिक कक्षा में परिवर्तन कर सकते हैं, तो डेवलपर्स उन परिवर्तनों को संलग्न करने के तरीके के भीतर दिखाई दे सकते हैं।

परिवर्तनीय अंतिम बनाना इन सभी संभावनाओं को हटा देता है - क्योंकि मूल्य को बिल्कुल बदला नहीं जा सकता है, आपको इस बारे में चिंता करने की आवश्यकता नहीं है कि ऐसे परिवर्तन दिखाई देंगे या नहीं। विधि और गुमनाम आंतरिक कक्षा को अनुमति देने का एकमात्र तरीका एक-दूसरे के परिवर्तनों को देखने के लिए कुछ विवरणों के एक परिवर्तनीय प्रकार का उपयोग करना है। यह संलग्न वर्ग स्वयं, एक सरणी, एक परिवर्तनीय रैपर प्रकार ... ऐसा कुछ भी हो सकता है। असल में यह एक विधि और दूसरे के बीच संचार की तरह थोड़ा सा है: एक विधि के पैरामीटर में किए गए परिवर्तन उसके कॉलर द्वारा नहीं देखे जाते हैं, लेकिन पैरामीटर द्वारा संदर्भित वस्तुओं में किए गए परिवर्तन देखे जाते हैं।

यदि आप जावा और सी # बंद होने के बीच अधिक विस्तृत तुलना में रूचि रखते हैं, तो मेरे पास एक article जो इसमें आगे जाता है। मैं इस जवाब में जावा पक्ष पर ध्यान केंद्रित करना चाहता था :)


private void f(Button b, final int a[]) {

    b.addClickHandler(new ClickHandler() {

        @Override
        public void onClick(ClickEvent event) {
            a[0] = a[0] * 5;

        }
    });
}

शायद यह चाल आपको एक विचार देता है

Boolean var= new anonymousClass(){
    private String myVar; //String for example
    @Overriden public Boolean method(int i){
          //use myVar and i
    }
    public String setVar(String var){myVar=var; return this;} //Returns self instane
}.setVar("Hello").method(3);






anonymous-class