एक अलग विधि में परिभाषित आंतरिक वर्ग के अंदर एक गैर-अंतिम चर को संदर्भित नहीं कर सकता


247

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

मैंने पहले लिखा था कि नीचे क्या है:

मुझे त्रुटि मिल रही है "एक अलग विधि में परिभाषित एक आंतरिक वर्ग के अंदर एक गैर-अंतिम चर को संदर्भित नहीं कर सकता है"।

यह दोहरे मूल्य और मूल्य नामक मूल्य के लिए हो रहा है। क्या आप जानते हैं कि मुझे यह समस्या क्यों है। मुझे समझ नहीं आ रहा है कि मुझे अंतिम घोषणा करने की आवश्यकता क्यों है। इसके अलावा अगर आप देख सकते हैं कि मैं यह करने की कोशिश कर रहा हूं, तो मुझे इस समस्या से निपटने के लिए क्या करना होगा।

public static void main(String args[]) {

    int period = 2000;
    int delay = 2000;

    double lastPrice = 0;
    Price priceObject = new Price();
    double price = 0;

    Timer timer = new Timer();

    timer.scheduleAtFixedRate(new TimerTask() {
        public void run() {
            price = priceObject.getNextPrice(lastPrice);
            System.out.println();
            lastPrice = price;
        }
    }, delay, period);
}

मैं जो पूछ रहा हूं वह यह है कि मुझे एक टाइमर में एक चर कैसे मिलेगा जिसे मैं लगातार अपडेट कर सकता हूं।
अंकुर

1
@ ठाकुर: सरल उत्तर "नहीं" है। लेकिन आप एक आंतरिक वर्ग का उपयोग करके वांछित प्रभाव प्राप्त कर सकते हैं; देखिए @ पेटरकार्डोना का जवाब।
स्टीफन सी

जवाबों:


197

जावा सही बंद का समर्थन नहीं करता है , भले ही आप यहाँ उपयोग कर रहे हैं जैसे एक अनाम वर्ग का उपयोग कर (new TimerTask() { ... } ) एक तरह के क्लोजर की तरह दिखता है।

संपादित करें - नीचे दिए गए टिप्पणियों को देखें - निम्नलिखित एक सही व्याख्या नहीं है, जैसा कि कीपरऑफTheSoul बताते हैं।

यही कारण है कि यह काम नहीं करता है:

lastPriceमुख्य () विधि में चर और मूल्य स्थानीय चर हैं। अनाम श्रेणी के साथ आपके द्वारा बनाई गई ऑब्जेक्ट main()विधि के वापस आने तक बनी रह सकती है।

जब main()विधि रिटर्न, स्थानीय चर (जैसे lastPriceऔर price) स्टैक से साफ किया जाएगा, ताकि वे के बाद अब मौजूद नहीं होगा main()रिटर्न।

लेकिन अनाम वर्ग ऑब्जेक्ट इन चरों का संदर्भ देता है। अगर अनाम वर्ग की वस्तु को साफ करने के बाद चर तक पहुंचने की कोशिश की जाती है, तो चीजें बहुत गलत होंगी।

बनाने lastPriceऔर price final, वे वास्तव में अब चर नहीं हैं, लेकिन स्थिरांक हैं। तब कंपाइलर केवल lastPriceऔर के उपयोग को बदल सकता हैprice स्थिरांक अनाम वर्ग में स्थिरांक (संकलित समय पर, निश्चित रूप से) के मूल्यों की , और आपको अब गैर-मौजूद चर तक पहुंचने की समस्या नहीं होगी।

अन्य प्रोग्रामिंग भाषाएं जो क्लोजर का समर्थन करती हैं, वे उन चरों को विशेष रूप से व्यवहार करते हुए करते हैं - यह सुनिश्चित करके कि वे विधि समाप्त होने पर नष्ट नहीं होते हैं, ताकि क्लोजर अभी भी चर तक पहुंच सके।

@ लखनऊ: आप ऐसा कर सकते हैं:

public static void main(String args[]) {
    int period = 2000;
    int delay = 2000;

    Timer timer = new Timer();

    timer.scheduleAtFixedRate(new TimerTask() {
        // Variables as member variables instead of local variables in main()
        private double lastPrice = 0;
        private Price priceObject = new Price();
        private double price = 0;

        public void run() {
            price = priceObject.getNextPrice(lastPrice);
            System.out.println();
            lastPrice = price;
        }
    }, delay, period);      
}

34
काफी हद तक सही नहीं है, जावा अपने रन-टाइम मानों को पकड़ने के लिए विचाराधीन चर उत्पन्न करता है, बस वे एक अजीब दुष्प्रभाव से बचना चाहते थे जो संभव है। नेट में जहां आप प्रतिनिधि में मूल्य पर कब्जा करते हैं, बदल जाते हैं। बाहरी विधि में मूल्य, और अब प्रतिनिधि नए मूल्य देखें, stackoverflow.com/questions/271440/c-captured-variable-in-loop को इस व्यवहार के सी # उदाहरण के लिए देखता है जिससे जावा बचने का लक्ष्य रखता है।
क्रिस चिल्वर्स

14
यह "अजीब साइड-इफ़ेक्ट" नहीं है, यह सामान्य व्यवहार है जिसकी लोग अपेक्षा करेंगे - और जो जावा वितरित नहीं कर सकता क्योंकि यह कैप्चर उत्पन्न नहीं करता है। वर्कअराउंड के रूप में, अनाम वर्ग में प्रयुक्त स्थानीय चर अंतिम होना चाहिए।
माइकल बॉर्गवर्ड

12
जेसपर, आपको संभवतः अपने उत्तरों के गलत हिस्सों को संपादित करना चाहिए, बल्कि केवल एक संदेश होने पर यह कहना चाहिए कि ऊपर गलत है।
जेम्स मैकमोहन

19
जावा, वास्तव में, समर्थन बंद नहीं करता है। जो भाषाएं बंद करने का समर्थन करती हैं, वे पूरे स्थानीय वातावरण (यानी, स्टैक फ्रेम में परिभाषित स्थानीय चर का समूह) को ढेर वस्तु के रूप में संग्रहीत करके करते हैं। जावा के पास इसके लिए समर्थन नहीं है (भाषा डिजाइनर इसे लागू करना चाहते थे लेकिन समय से बाहर भाग गए), इसलिए वर्कअराउंड के रूप में, जब भी किसी स्थानीय वर्ग को त्वरित किया जाता है, तो किसी भी स्थानीय चर के मूल्यों को संदर्भित करता है, जिसे ढेर पर कॉपी किया जाता है। । हालाँकि, JVM तब लोकल वैरिएबल के साथ तालमेल नहीं रख पाता है, जिसके कारण उन्हें फाइनल होना पड़ता है।
तैमूर

64
यह उत्तर अब पूरी तरह से भ्रमित करने वाला है कि "KeeperOfTheSoul" नाम का कोई नहीं है जिसने इस पर टिप्पणी की है। उत्तर को संशोधित किया जाना चाहिए।
एडम पार्किं

32

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

यह स्पष्ट रूप से आपके लिए काम नहीं करेगा क्योंकि आप उन्हें बदलना चाहते हैं, इस मामले में आपको उन्हें एक वर्ग के भीतर एनकैप्सुलेट करना चाहिए।

public class Foo {
    private PriceObject priceObject;
    private double lastPrice;
    private double price;

    public Foo(PriceObject priceObject) {
        this.priceObject = priceObject;
    }

    public void tick() {
        price = priceObject.getNextPrice(lastPrice);
        lastPrice = price;
    }
}

अब केवल अंतिम के रूप में एक नया फू बनाएं और टाइमर से क्लिक करें।

public static void main(String args[]){
    int period = 2000;
    int delay = 2000;

    Price priceObject = new Price();
    final Foo foo = new Foo(priceObject);

    Timer timer = new Timer();
    timer.scheduleAtFixedRate(new TimerTask() {
        public void run() {
            foo.tick();
        }
    }, delay, period);
}

1
या आप बस फू को लागू करने योग्य नेतृत्व कर सकते हैं ..?
vidstige

18

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

तो आपके विकल्प एक वास्तविक आंतरिक वर्ग बनाने के लिए हैं, जिसमें आप चर में पास हो सकते हैं और सामान्य फैशन में उनका उपयोग कर सकते हैं

या:

आपके lastPrice और प्राइस वैरिएबल के लिए एक त्वरित (और मेरी राय में बदसूरत) हैक है जो इसे घोषित करना है

final double lastPrice[1];
final double price[1];

और अपने अनाम वर्ग में आप इस तरह से मान सेट कर सकते हैं

price[0] = priceObject.getNextPrice(lastPrice[0]);
System.out.println();
lastPrice[0] = price[0];

14

आप जो पहले से ही प्रदान करने की कोशिश कर रहे हैं उसे आप क्यों नहीं कर सकते, इसके लिए अच्छे स्पष्टीकरण। समाधान के रूप में, शायद विचार करें:

public class foo
{
    static class priceInfo
    {
        public double lastPrice = 0;
        public double price = 0;
        public Price priceObject = new Price ();
    }

    public static void main ( String args[] )
    {

        int period = 2000;
        int delay = 2000;

        final priceInfo pi = new priceInfo ();
        Timer timer = new Timer ();

        timer.scheduleAtFixedRate ( new TimerTask ()
        {
            public void run ()
            {
                pi.price = pi.priceObject.getNextPrice ( pi.lastPrice );
                System.out.println ();
                pi.lastPrice = pi.price;

            }
        }, delay, period );
    }
}

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


11

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

इस कोड को उदाहरण के लिए लें:

public class EnclosingClass {
    public void someMethod() {
        String shared = "hello"; 
        new Thread() {
            public void run() {
                // this is not valid, won't compile
                System.out.println(shared); // this instance expects shared to point to the reference where the String object "hello" lives in heap
            }
        }.start();

        // change the reference 'shared' points to, with a new value
        shared = "other hello"; 
        System.out.println(shared);
    }
}

यह काम नहीं करेगा, क्योंकि यह वह है जो कंपाइलर हुड के नीचे करता है:

public void someMethod() {
    String shared = "hello"; 
    new EnclosingClass$1(shared).start();

    // change the reference 'shared' points to, with a new value
    shared = "other hello"; 
    System.out.println(shared);
}

मूल अनाम वर्ग को कुछ स्टैंडअलोन वर्ग द्वारा प्रतिस्थापित किया जाता है जो संकलक उत्पन्न करता है (कोड सटीक नहीं है, लेकिन आपको एक अच्छा विचार देना चाहिए:

public class EnclosingClass$1 extends Thread {
    String shared;
    public EnclosingClass$1(String shared) {
        this.shared = shared;
    }

    public void run() {
        System.out.println(shared);
    }
}

जैसा कि आप देख सकते हैं, स्टैंडअलोन वर्ग साझा किए गए ऑब्जेक्ट का एक संदर्भ रखता है, याद रखें कि जावा में सब कुछ पास-बाय-वैल्यू है, इसलिए भले ही EnclosingClass में संदर्भ चर 'साझा' बदल जाता है, तो यह इंगित करता है कि संशोधित नहीं किया गया है , और अन्य सभी संदर्भ चर इसकी ओर इशारा करते हैं (जैसे अनाम श्रेणी में एक: $ 1 संलग्न करना), इसके बारे में पता नहीं होगा। यह मुख्य कारण है कि कंपाइलर आपको इस 'साझा' चर को अंतिम घोषित करने के लिए मजबूर करता है, ताकि इस प्रकार का व्यवहार आपके पहले से चल रहे कोड में न बने।

अब, ऐसा तब होता है जब आप एक अनाम वर्ग के अंदर एक इंस्टेंस वेरिएबल का उपयोग करते हैं (यह वही है जो आपको अपनी समस्या को हल करने के लिए करना चाहिए, अपने तर्क को "उदाहरण" विधि या किसी वर्ग के निर्माता के लिए ले जाएँ):

public class EnclosingClass {
    String shared = "hello";
    public void someMethod() {
        new Thread() {
            public void run() {
                System.out.println(shared); // this is perfectly valid
            }
        }.start();

        // change the reference 'shared' points to, with a new value
        shared = "other hello"; 
        System.out.println(shared);
    }
}

यह ठीक संकलित करता है, क्योंकि संकलक कोड को संशोधित करेगा, ताकि $ 1 का नया उत्पन्न वर्ग EnclosingClass के उदाहरण के लिए एक संदर्भ रखेगा जहां यह त्वरित था (यह केवल एक प्रतिनिधित्व है, लेकिन आपको जाना चाहिए:

public void someMethod() {
    new EnclosingClass$1(this).start();

    // change the reference 'shared' points to, with a new value
    shared = "other hello"; 
    System.out.println(shared);
}

public class EnclosingClass$1 extends Thread {
    EnclosingClass enclosing;
    public EnclosingClass$1(EnclosingClass enclosing) {
        this.enclosing = enclosing;
    }

    public void run() {
        System.out.println(enclosing.shared);
    }
}

इस तरह, जब EnclosingClass में रेफरेंस वैरिएबल 'शेयर' हो जाता है, तो पुन: असाइन किया जाता है, और थ्रेड # रन () पर कॉल करने से पहले ऐसा होता है, आपको "अन्य हेलो" दो बार मुद्रित दिखाई देगा, क्योंकि अब EnclosingClass $ 1 # एन्कोडिंग चर एक संदर्भ रखेगा। जिस कक्षा में यह घोषित किया गया था, उस ऑब्जेक्ट के लिए, इसलिए उस ऑब्जेक्ट पर किसी भी विशेषता में परिवर्तन EnclosingClass $ 1 के उदाहरणों को दिखाई देगा।

विषय पर अधिक जानकारी के लिए, आप इस उत्कृष्ट ब्लॉग पोस्ट (मेरे द्वारा नहीं लिखी गई) को देख सकते हैं: http://kevinboone.net/java_inner.html


क्या होगा यदि स्थानीय चर 'साझा' एक परस्पर वस्तु है? आपके स्पष्टीकरण के अनुसार 'अंतिम' घोषित करने से कोई मदद नहीं मिलेगी, है ना?
sactiw

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

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

1
बेशक ओपी एक उत्परिवर्तित वस्तु के तहत आवश्यक मूल्य को लपेट सकता है, चर को अंतिम घोषित कर सकता है और इसके बजाय इसका उपयोग कर सकता है। हालांकि, वह चर को वर्तमान वर्ग की विशेषता के रूप में घोषित करके एक अतिरिक्त वस्तु का उपयोग करने से बच सकता है (जैसा कि उत्तर में बताया गया है और समझाया गया है)। उत्परिवर्तनीय वस्तुओं को मजबूर करना (जैसे सरणियों का उपयोग केवल एक साझा चर के मूल्य को संशोधित करने में सक्षम होना) एक अच्छा विचार नहीं है।
एमिनो 21'17

7

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

संपादित करें: वास्तव में, मैं एक अनाम वर्ग का उपयोग नहीं करता, लेकिन एक उचित उपवर्ग:

public class PriceData {
        private double lastPrice = 0;
        private double price = 0;

        public void setlastPrice(double lastPrice) {
            this.lastPrice = lastPrice;
        }

        public double getLastPrice() {
            return lastPrice;
        }

        public void setPrice(double price) {
            this.price = price;
        }

        public double getPrice() {
            return price;
        }
    }

    public class PriceTimerTask extends TimerTask {
        private PriceData priceData;
        private Price priceObject;

        public PriceTimerTask(PriceData priceData, Price priceObject) {
            this.priceData = priceData;
            this.priceObject = priceObject;
        }

        public void run() {
            priceData.setPrice(priceObject.getNextPrice(lastPrice));
            System.out.println();
            priceData.setLastPrice(priceData.getPrice());

        }
    }

    public static void main(String args[]) {

        int period = 2000;
        int delay = 2000;

        PriceData priceData = new PriceData();
        Price priceObject = new Price();

        Timer timer = new Timer();

        timer.scheduleAtFixedRate(new PriceTimerTask(priceData, priceObject), delay, period);
    }

2

आप गैर-अंतिम चर का संदर्भ नहीं दे सकते क्योंकि जावा भाषा विनिर्देश ऐसा कहता है। 8.1.3 से:
"किसी भी स्थानीय चर, औपचारिक विधि पैरामीटर या अपवाद हैंडलर पैरामीटर का उपयोग किया जाता है लेकिन आंतरिक वर्ग में घोषित नहीं किया जाना चाहिए।" पूरा पैराग्राफ।
मैं आपके कोड का केवल एक हिस्सा देख सकता हूं - मेरे अनुसार स्थानीय चर का शेड्यूलिंग संशोधन एक अजीब विचार है। जब आप फ़ंक्शन छोड़ते हैं तो स्थानीय चर मौजूद नहीं होते हैं। शायद एक वर्ग के स्थिर क्षेत्र बेहतर होंगे?


2

मैंने लेखकों के इरादे से कुछ संभालने के लिए बस कुछ लिखा । मुझे सबसे अच्छी बात यह लगी कि कंस्ट्रक्टर को लेने देना था सभी ऑब्जेक्ट्स को और फिर आपके कार्यान्वित तरीके में उस कंस्ट्रक्टर ऑब्जेक्ट्स का उपयोग करना था।

हालांकि, यदि आप एक सामान्य इंटरफ़ेस क्लास लिख रहे हैं, तो आपको ऑब्जेक्ट पास करना होगा, या ऑब्जेक्ट्स की एक सूची को बेहतर बनाना होगा। यह ऑब्जेक्ट [] या इससे भी बेहतर हो सकता है, ऑब्जेक्ट ... क्योंकि यह कॉल करना आसान है।

नीचे मेरा उदाहरण टुकड़ा देखें।

List<String> lst = new ArrayList<String>();
lst.add("1");
lst.add("2");        

SomeAbstractClass p = new SomeAbstractClass (lst, "another parameter", 20, true) {            

    public void perform( ) {                           
        ArrayList<String> lst = (ArrayList<String>)getArgs()[0];                        
    }

};

public abstract class SomeAbstractClass{    
    private Object[] args;

    public SomeAbstractClass(Object ... args) {
        this.args = args;           
    }      

    public abstract void perform();        

    public Object[] getArgs() {
        return args;
    }

}

कृपया इस पोस्ट को जावा क्लोजर के बारे में देखें जो इस बॉक्स से बाहर का समर्थन करता है: http://mseifed.blogspot.se/2012/09/closure-implementation-for-java-5-6-and.html

संस्करण 1 ऑटोकस्टिंग के साथ नॉन-फाइनल क्लोजर पास करने का समर्थन करता है:
https://github.com/MSeifeddo/Closure-implementation-for-Java-5-6-and-7/blob/master/org/mo/clouble-v1/ Closure.java

    SortedSet<String> sortedNames = new TreeSet<String>();
    // NOTE! Instead of enforcing final, we pass it through the constructor
    eachLine(randomFile0, new V1<String>(sortedNames) {
        public void call(String line) {
            SortedSet<String> sortedNames = castFirst();  // Read contructor arg zero, and auto cast it
            sortedNames.add(extractName(line));
        }
    });

2

यदि आप एक अनाम वर्ग के भीतर एक विधि कॉल में एक मूल्य बदलना चाहते हैं, तो वह "मूल्य" वास्तव में एक है Future। इसलिए, यदि आप अमरूद का उपयोग करते हैं, तो आप लिख सकते हैं

...
final SettableFuture<Integer> myvalue = SettableFuture<Integer>.create();
...
someclass.run(new Runnable(){

    public void run(){
        ...
        myvalue.set(value);
        ...
    }
 }

 return myvalue.get();

2

एक समाधान जो मैंने देखा है, उसका उल्लेख नहीं किया गया है (जब तक कि मैंने इसे याद नहीं किया, अगर मैंने मुझे सही किया), एक वर्ग चर का उपयोग है। इस समस्या में एक विधि के भीतर एक नया सूत्र चलाने का प्रयास किया गया:new Thread(){ Do Something } :।

doSomething()निम्न में से कॉल करने से काम चल जाएगा। आपको इसे घोषित करने की आवश्यकता नहीं है final, बस चर के दायरे को बदलने की आवश्यकता है ताकि यह इनरक्लास से पहले एकत्र न हो। यह तब तक है जब तक कि आपकी प्रक्रिया बहुत बड़ी न हो और गुंजाइश बदलने से कुछ प्रकार के संघर्ष पैदा हो सकते हैं। मैं अपने चर को अंतिम नहीं बनाना चाहता था क्योंकि यह किसी भी तरह से अंतिम / स्थिर नहीं था।

public class Test
{

    protected String var1;
    protected String var2;

    public void doSomething()
    {
        new Thread()
        {
            public void run()
            {
                System.out.println("In Thread variable 1: " + var1);
                System.out.println("In Thread variable 2: " + var2);
            }
        }.start();
    }

}

1

यदि अंतिम होने के लिए आवश्यक चर नहीं हो सकता है, तो आप चर के मूल्य को दूसरे चर में निर्दिष्ट कर सकते हैं और THAT को अंतिम बना सकते हैं ताकि आप इसके बजाय इसका उपयोग कर सकें।


1

गैर-अंतिम चर का संदर्भ देने के लिए ClassName.this.variableName का उपयोग करें


1

आप केवल बाहरी वर्ग के बाहर चर घोषित कर सकते हैं। इसके बाद, आप भीतर के वर्ग से चर को संपादित करने में सक्षम होंगे। मुझे कभी-कभी एंड्रॉइड में कोडिंग करते समय समान समस्याओं का सामना करना पड़ता है इसलिए मैं वैरिएबल को वैश्विक घोषित करता हूं और यह मेरे लिए काम करता है।


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


0

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

public class WorkerService extends Service {

Worker _worker;
ExecutorService _executorService;
ScheduledExecutorService _scheduledStopService;

TextView _statusTextView;


@Override
public void onCreate() {
    _worker = new Worker(this);
    _worker.monitorGpsInBackground();

    // To get a thread pool service containing merely one thread
    _executorService = Executors.newSingleThreadExecutor();

    // schedule something to run in the future
    _scheduledStopService = Executors.newSingleThreadScheduledExecutor();
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {

    ServiceRunnable runnable = new ServiceRunnable(this, startId);
    _executorService.execute(runnable);

    // the return value tells what the OS should
    // do if this service is killed for resource reasons
    // 1. START_STICKY: the OS restarts the service when resources become
    // available by passing a null intent to onStartCommand
    // 2. START_REDELIVER_INTENT: the OS restarts the service when resources
    // become available by passing the last intent that was passed to the
    // service before it was killed to onStartCommand
    // 3. START_NOT_STICKY: just wait for next call to startService, no
    // auto-restart
    return Service.START_NOT_STICKY;
}

@Override
public void onDestroy() {
    _worker.stopGpsMonitoring();
}

@Override
public IBinder onBind(Intent intent) {
    return null;
}

class ServiceRunnable implements Runnable {

    WorkerService _theService;
    int _startId;
    String _statusMessage;

    public ServiceRunnable(WorkerService theService, int startId) {
        _theService = theService;
        _startId = startId;
    }

    @Override
    public void run() {

        _statusTextView = MyActivity.getActivityStatusView();

        // get most recently available location as a latitude /
        // longtitude
        Location location = _worker.getLocation();
        updateStatus("Starting");

        // convert lat/lng to a human-readable address
        String address = _worker.reverseGeocode(location);
        updateStatus("Reverse geocoding");

        // Write the location and address out to a file
        _worker.save(location, address, "ResponsiveUx.out");
        updateStatus("Done");

        DelayedStopRequest stopRequest = new DelayedStopRequest(_theService, _startId);

        // schedule a stopRequest after 10 seconds
        _theService._scheduledStopService.schedule(stopRequest, 10, TimeUnit.SECONDS);
    }

    void updateStatus(String message) {
        _statusMessage = message;

        if (_statusTextView != null) {
            _statusTextView.post(new Runnable() {

                @Override
                public void run() {
                    _statusTextView.setText(_statusMessage);

                }

            });
        }
    }

}

0

मेरे लिए जो काम किया है वह सिर्फ आपके इस कार्य के बाहर चर को परिभाषित करता है।

मुख्य कार्य घोषित होने से ठीक पहले

Double price;
public static void main(String []args(){
--------
--------
}

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

0

वैरिएबल को एक स्थिर के रूप में घोषित करें और className.variable का उपयोग करके आवश्यक विधि में संदर्भ दें


Non-static parameter cannot be referenced from a static context
स्टीफन

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

0

बस एक और स्पष्टीकरण। नीचे इस उदाहरण पर विचार करें

public class Outer{
     public static void main(String[] args){
         Outer o = new Outer();
         o.m1();        
         o=null;
     }
     public void m1(){
         //int x = 10;
         class Inner{
             Thread t = new Thread(new Runnable(){
                 public void run(){
                     for(int i=0;i<10;i++){
                         try{
                             Thread.sleep(2000);                            
                         }catch(InterruptedException e){
                             //handle InterruptedException e
                         }
                         System.out.println("Thread t running");                             
                     }
                 }
             });
         }
         new Inner().t.start();
         System.out.println("m1 Completes");
    }
}

यहां आउटपुट होगा

m1 पूरा करता है

थ्रेड टी रनिंग

थ्रेड टी रनिंग

थ्रेड टी रनिंग

................

अब मेथड एम 1 () पूरा हो गया है और हम रेफरेंस वेरिएबल ओ को null करने के लिए असाइन करते हैं। अब आउटर क्लास ऑब्जेक्ट GC के लिए योग्य है, लेकिन इनर क्लास ऑब्जेक्ट अभी भी मौजूद है, जिसके थ्रेड ऑब्जेक्ट के साथ (Has-A) संबंध है जो चल रहा है। मौजूदा बाहरी वर्ग वस्तु के बिना मौजूदा m1 () विधि का कोई मौका नहीं है और मौजूदा m1 () विधि के बिना इसके स्थानीय चर का कोई मौका नहीं है, लेकिन अगर भीतरी वर्ग वस्तु m1 () विधि के स्थानीय चर का उपयोग करता है तो सब कुछ स्वयं व्याख्यात्मक है ।

इसे हल करने के लिए हमें स्थानीय वैरिएबल की एक प्रति बनानी होगी और फिर कॉपी करना होगा, इनर क्लास ऑब्जेक्ट के साथ ढेर में, जावा केवल अंतिम चर के लिए क्या करता है क्योंकि वे वास्तव में वैरिएबल नहीं हैं जैसे वे स्थिरांक की तरह हैं (सब कुछ केवल संकलन समय पर होता है रनटाइम पर नहीं)।


-1

उपरोक्त समस्या को हल करने के लिए, विभिन्न भाषाएं अलग-अलग निर्णय लेती हैं।

जावा के लिए, समाधान इस लेख में जैसा हम देखते हैं वैसा ही है।

C # के लिए, समाधान को साइड-इफ़ेक्ट की अनुमति है और संदर्भ द्वारा कैप्चर करना एकमात्र विकल्प है।

C ++ 11 के लिए, समाधान प्रोग्रामर को निर्णय लेने की अनुमति देने के लिए है। वे मूल्य या संदर्भ से कैप्चर करना चुन सकते हैं। यदि मूल्य द्वारा कैप्चरिंग, कोई साइड-इफेक्ट नहीं होता है क्योंकि संदर्भित चर वास्तव में अलग है। यदि संदर्भ द्वारा कैप्चर किया जाता है, तो साइड-इफेक्ट्स हो सकते हैं लेकिन प्रोग्रामर को इसका एहसास होना चाहिए।


-2

क्योंकि यह भ्रमित हो रहा है कि चर अंतिम नहीं है, क्योंकि इसमें परिवर्तन अनाम वर्ग में नहीं उठाए जाएंगे।

बस चर 'कीमत' और 'lastPrice' को अंतिम रूप दें।

- संपादित करें

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


2
इसकी भ्रामक नहीं है - इसका सर्वथा गलत, इस प्रकार संकलक इसकी अनुमति नहीं देता है।
Chii

लेकिन तब मुझे उन मूल्यों को कैसे बदलना चाहिए जब मुझे ज़रूरत होती है?
अंकुर

सिर्फ इसलिए नहीं कि यह भ्रामक है; यह इसलिए है क्योंकि जावा बंद होने का समर्थन नहीं करता है। नीचे मेरा जवाब देखें। @Ankur: आप मुख्य () में स्थानीय चर के बजाय अनाम वर्ग ऑब्जेक्ट के चर सदस्य चर बना सकते हैं।
जेसपर

वह उन्हें संशोधित कर रहा है, इसलिए वे अंतिम नहीं हो सकते।
रॉबिन

यदि मूल्य और अंतिम भुगतान अंतिम थे, तो उन्हें असाइनमेंट संकलित नहीं होगा।
ग्रेग मैट
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.