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