इसका कारण यह है कि जिस तरह से गुमनाम वर्गों लागू किया जाता है की होती है। आप यह देखते हैं आप कोड के लिए एक मामूली परिवर्तन करने के लिए और फिर डिकंपाइल कर सकते हैं:
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
की चर्चा करते हुए अनुमति दी गई थी, तो आप इस लिखने में सक्षम हो जाएगा। इसलिए, उस चर का जिक्र करने की अनुमति नहीं है।
सच अच्छा! Decompiled 'उदाहरण $ 1' वर्ग होने के कारण बहुत कुछ दिखाता है _why_ 'अन्य' होना चाहिए 'अंतिम'। यदि यह नहीं था, तो 'उदाहरण $ 1' संभावित रूप से' अन्य 'की पुरानी प्रतिलिपि से निपट सकता है, जो कम से कम कहने के लिए ... अजीब होगा। –