2016-02-04 10 views
5

यह self-answered questionVariable 'snackbar' might not have been initialized से प्रेरित था। मुझे लगा कि वहां अधिक जानकारी थी जो उस विशिष्ट प्रश्न से बेहतर जोड़ा जाएगा।"वेरिएबल उदाहरण प्रारंभ नहीं किया जा सकता है" अज्ञात वर्ग

निम्नलिखित कोड क्यों संकलित नहीं किया जा सकता है?

public class Example { 
    public static void main(String[] args) { 
    final Runnable example = new Runnable() { 
     @Override 
     public void run() { 
     System.out.println(example); // Error on this line 
     } 
    }; 
    } 
} 

संकलन त्रुटि:

error: variable example might not have been initialized 

उत्तर

8

इसका कारण यह है कि जिस तरह से गुमनाम वर्गों लागू किया जाता है की होती है। आप यह देखते हैं आप कोड के लिए एक मामूली परिवर्तन करने के लिए और फिर डिकंपाइल कर सकते हैं:

final Runnable other = null; 
    final Runnable example = new Runnable() { 
     @Override 
     public void run() { 
     System.out.println(other); 
     } 
    }; 

अर्थात गुमनाम वर्ग एक अलग स्थानीय चर का उल्लेख कर सकते हैं। यह अब संकलित होगा; हम javap का उपयोग कर डिकंपाइल और अनाम वर्ग के इंटरफ़ेस देख सकते हैं:

final class Example$1 implements java.lang.Runnable { 
    final java.lang.Runnable val$other; 
    Example$1(java.lang.Runnable); 
    public void run(); 
} 

(Example$1 नाम है जिसके द्वारा जावा आंतरिक रूप से गुमनाम श्रेणी को संदर्भित करता है)।

इससे पता चलता है कि कंपाइलर ने अज्ञात वर्ग में एक कन्स्ट्रक्टर जोड़ा है जो Runnable पैरामीटर लेता है; इसमें val$other नामक एक फ़ील्ड भी है। इस क्षेत्र के इस नाम को संकेत देना चाहिए कि यह फ़ील्ड other स्थानीय चर से संबंधित है।

आप बाईटकोड आगे में खुदाई कर सकते हैं और देखते हैं कि इस पैरामीटर val$other को सौंपा गया है:

Example$1(java.lang.Runnable); 
    Code: 
     0: aload_0 
     // This gets the parameter... 
     1: aload_1 
     // ...and this assigns it to the field val$other 
     2: putfield  #1     // Field val$other:Ljava/lang/Runnable; 
     5: aload_0 
     6: invokespecial #2     // Method java/lang/Object."<init>":()V 
     9: return 

तो, क्या इस से पता चलता है कि जिस तरह से गुमनाम कक्षाएं उनके enclosing दायरे से चर का उपयोग है: वे कर रहे हैं बस निर्माण समय पर मूल्य पारित किया।

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

final Runnable example = new Runnable() { ... } 

पूरी तरह से पहले दाएँ हाथ की ओर का मूल्यांकन, और फिर बाएं हाथ की ओर पर चर निर्दिष्ट करने के लिए है। ,

final Runnable example = new Example$1(example); 

example पहले से घोषित नहीं किया गया है कि एक समस्या नहीं है के बाद से इस कोड है: हालांकि, यह Runnable$1 के उत्पन्न निर्माता में पारित करने के लिए दाएँ हाथ की ओर पर चर के मूल्य की जरूरत है शब्दार्थतः पहचान करने के लिए:

final Runnable example; 
example = new Example$1(example); 

तो त्रुटि है कि आप प्राप्त है कि चर नहीं सुलझाया जा सकता है नहीं है - एक से पहले ही, इसलिए निर्माता के लिए एक तर्क के रूप में प्रयोग किया जाता मूल्य हालांकि, example सौंपा नहीं किया गया है कंपाइलर त्रुटि।


यह तर्क दिया जा सकता है कि यह केवल एक कार्यान्वयन विस्तार है: इससे कोई फर्क नहीं करना चाहिए तर्क, निर्माता में प्रदान किया जाने के रूप में वहाँ कोई रास्ता नहीं है कि run() विधि से पहले लागू किया जा सकता है है असाइनमेंट। , इस प्रकार आप काम से पहले run() आह्वान कर सकते हैं:

वास्तव में, कि नहीं सच है

final Runnable example = new Runnable() { 
    Runnable runAndReturn() { 
    run(); 
    return this; 
    } 

    @Override public void run() { 
    System.out.println(example); 
    } 
}.runAndReturn(); 

तो गुमनाम वर्ग के अंदर example की चर्चा करते हुए अनुमति दी गई थी, तो आप इस लिखने में सक्षम हो जाएगा। इसलिए, उस चर का जिक्र करने की अनुमति नहीं है।

+0

सच अच्छा! Decompiled 'उदाहरण $ 1' वर्ग होने के कारण बहुत कुछ दिखाता है _why_ 'अन्य' होना चाहिए 'अंतिम'। यदि यह नहीं था, तो 'उदाहरण $ 1' संभावित रूप से' अन्य 'की पुरानी प्रतिलिपि से निपट सकता है, जो कम से कम कहने के लिए ... अजीब होगा। –

4

आप का उपयोग "इस" संकलन त्रुटि से बचने के लिए कर सकते हैं:

final Runnable example = new Runnable() { 
    @Override 
    public void run() { 
    System.out.println(this); // Use "this" on this line 
    } 
}; 
संबंधित मुद्दे