2010-07-14 15 views
9

मैं अपने अज्ञात आंतरिक उपclass में इस विधि को userId का मान कैसे प्राप्त कर सकता हूं?जावा: स्थानीय चर का उपयोग कर बेनामी आंतरिक वर्ग

Cannot refer to a non-final variable userID inside an inner class defined in a different method

मैं यकीन है कि क्योंकि यह एक अज्ञात मूल्य के साथ एक चर है मैं अंतिम रूप में निर्दिष्ट नहीं कर सकते:

public void doStuff(String userID) { 
    doOtherStuff(userID, new SuccessDelegate() { 
     @Override 
     public void onSuccess() { 
      Log.e(TAG, "Called delegate!!!! "+ userID); 
     } 
    }); 
} 

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

+0

बहुत खराब जावा को यहां अंतिम आवश्यकता है। यह संकलक के लिए स्पष्ट है कि स्थानीय चर बदल नहीं है, इसे कोडर से इसकी पुष्टि करने के लिए नहीं कहना चाहिए। यदि एनन क्लास स्थानीय चर में लिखता है, तो संकलन चेतावनी पर्याप्त है। बुरा बुरा डिजाइन पसंद। – irreputable

+0

संभावित डुप्लिकेट [अज्ञात वर्ग में केवल अंतिम चर उपलब्ध क्यों हैं?] (Http://stackoverflow.com/questions/4732544/why-are-only-final-variables-accessible-in-anonymous-class) – vaxquis

उत्तर

7

सुनिश्चित करें कि आप अंतिम के रूप में निर्दिष्ट कर सकते हैं - बस पैरामीटर की घोषणा में उस कीवर्ड डाल:

public void doStuff(final String userID) { 
    ... 

मुझे यकीन है कि आप इसे एक अज्ञात मूल्य के साथ एक चर होने के बारे में क्या मतलब नहीं हूँ, सभी अंतिम साधन यह है कि एक बार वैरिएबल को मान दिया जाता है, यह री -assigned नहीं हो सकता है। चूंकि आप अपनी विधि के भीतर उपयोगकर्ता आईडी के मूल्य को नहीं बदल रहे हैं, इसलिए इस मामले में इसे अंतिम बनाने में कोई समस्या नहीं है।

+0

आह ठीक है । मुझे लगता है कि मैं वास्तव में समझ नहीं पाया कि 'अंतिम' घोषणा कैसे काम करती है। धन्यवाद। –

1

क्या यह final

public void doStuff (final String userID) 
1

में के रूप में बनाने के साथ समस्या है विधि

public void doStuff(final String userID) 

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

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

10

जैसा कि यहां हर किसी ने कहा है, स्थानीय चर को आंतरिक कक्षा द्वारा एक्सेस किया जाना अंतिम है।

यहाँ

है (मूल रूप से) ऐसा क्यों है ... यदि आप तल पर निम्नलिखित कोड (उत्तर है, लेकिन, लिखते हैं, आप प्राप्त कर सकते हैं लघु संस्करण :-):

class Main 
{ 
    private static interface Foo 
    { 
     void bar(); 
    } 

    public static void main(String[] args) 
    { 
     final int x; 
     Foo foo; 

     x = 42; 
     foo = new Foo() 
     { 
      public void bar() 
      { 
       System.out.println(x); 
      } 
     }; 

     foo.bar(); 
    } 
} 

संकलक यह मोटे तौर पर तब्दील हो इस तरह:

class Main 
{ 
    private static interface Foo 
    { 
     void bar(); 
    } 

    public static void main(String[] args) 
    { 
     final int x; 
     Foo foo; 

     x = 42; 

     class $1 
      implements Foo 
     { 
      public void bar() 
      { 
       System.out.println(x); 
      } 
     } 

     foo = new $1(); 
     foo.bar(); 
    } 
} 

और फिर इस:

class Main 
{ 
    private static interface Foo 
    { 
     void bar(); 
    } 

    public static void main(String[] args) 
    { 
     final int x; 
     Foo foo; 

     x = 42; 
     foo = new $1(x); 
     foo.bar(); 
    } 

    private static class $1 
     implements Foo 
    { 
     private final int x; 

     $1(int val) 
     { 
      x = val; 
     } 

     public void bar() 
     { 
      System.out.println(x); 
     } 
    } 
} 

और यह करने के लिए अंत में:

class Main 
{ 
    public static void main(String[] args) 
    { 
     final int x; 
     Main$Foo foo; 

     x = 42; 
     foo = new Main$1(x); 
     foo.bar(); 
    } 
} 

interface Main$Foo 
{ 
    void bar(); 
} 

class Main$1 
    implements Main$Foo 
{ 
    private final int x; 

    Main$1(int val) 
    { 
     x = val; 
    } 

    public void bar() 
    { 
     System.out.println(x); 
    } 
} 

महत्वपूर्ण यह वह जगह है जहां यह $ 1 को कन्स्ट्रक्टर जोड़ता है। कल्पना कीजिए कि अगर आप ऐसा कर सकता है:

class Main 
{ 
    private static interface Foo 
    { 
     void bar(); 
    } 

    public static void main(String[] args) 
    { 
     int x; 
     Foo foo; 

     x = 42; 
     foo = new Foo() 
     { 
      public void bar() 
      { 
       System.out.println(x); 
      } 
     }; 

     x = 1; 

     foo.bar(); 
    } 
} 

आपको लगता है कि foo.bar() उम्मीद करेंगे बाहर 1 मुद्रित होगा लेकिन यह वास्तव में बाहर 42 प्रिंट होगा अंतिम इस भ्रामक स्थिति पैदा होती है नहीं कर सकते हैं होने के लिए स्थानीय चर की आवश्यकता द्वारा।

+0

प्रश्न: एनोन आंतरिक कक्षा केवल 'अंतिम' स्थानीय चर के स्वचालित प्रतियां बनाती है जो यह सही उपयोग करती है? अन्य स्थानीय (अंतिम या नहीं) चर की प्रतियां नहीं हैं जिनका उपयोग सीधे नहीं किया जाता है? मैं पूछता हूं क्योंकि मैं स्मृति रिसाव के बारे में चिंतित हूं। –

1

जावा 8 में, यह थोड़ा सा बदल गया है। अब आप उन चरों तक पहुंच सकते हैं जो प्रभावी रूप से अंतिम हैं।Oracle documentation (जोर मेरा) से प्रासंगिक स्निपेट और उदाहरण:

However, starting in Java SE 8, a local class can access local variables and parameters of the enclosing block that are final or effectively final. A variable or parameter whose value is never changed after it is initialized is effectively final. For example, suppose that the variable numberLength is not declared final, and you add the highlighted assignment statement in the PhoneNumber constructor:

PhoneNumber(String phoneNumber) { 
    numberLength = 7; // From Kobit: this would be the highlighted line 
    String currentNumber = phoneNumber.replaceAll(
     regularExpression, ""); 
    if (currentNumber.length() == numberLength) 
     formattedPhoneNumber = currentNumber; 
    else 
     formattedPhoneNumber = null; 
} 

Because of this assignment statement, the variable numberLength is not effectively final anymore. As a result, the Java compiler generates an error message similar to "local variables referenced from an inner class must be final or effectively final" where the inner class PhoneNumber tries to access the numberLength variable:

if (currentNumber.length() == numberLength) 

Starting in Java SE 8, if you declare the local class in a method, it can access the method's parameters. For example, you can define the following method in the PhoneNumber local class:

public void printOriginalNumbers() { 
    System.out.println("Original numbers are " + phoneNumber1 + 
     " and " + phoneNumber2); 
} 

The method printOriginalNumbers accesses the parameters phoneNumber1 and phoneNumber2 of the method validatePhoneNumber

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