বেনাম ক্লাস সহ, আপনি আসলে একটি "নামহীন" নেস্টেড ক্লাস ঘোষণা করছেন। নেস্টেড ক্লাসগুলির জন্য, সংকলকটি কনস্ট্রাক্টরের সাথে একটি নতুন স্ট্যান্ডেলোন পাবলিক ক্লাস তৈরি করে যা এটি আর্গুমেন্ট হিসাবে ব্যবহার করে এমন সমস্ত ভেরিয়েবল গ্রহণ করবে ("নামযুক্ত" নেস্টেড ক্লাসগুলির জন্য, এটি সর্বদা আসল / ঘেরযুক্ত শ্রেণীর উদাহরণ)। এটি করা হয়েছে কারণ রানটাইম পরিবেশে নেস্টেড ক্লাসগুলির কোনও ধারণা নেই, তাই নেস্টেড থেকে স্ট্যান্ডেলোন ক্লাসে একটি (স্বয়ংক্রিয়) রূপান্তর হওয়া দরকার।
উদাহরণস্বরূপ এই কোডটি নিন:
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);
}
}
যেমন আপনি দেখতে পাচ্ছেন, স্ট্যান্ডেলোন ক্লাসটি ভাগ করা বস্তুর রেফারেন্স রাখে, মনে রাখবেন জাভাতে সমস্ত কিছুই পাস-বাই-ভ্যালু, সুতরাং এনক্লোসিংক্লাসে রেফারেন্স ভেরিয়েবল 'ভাগ করা' পরিবর্তিত হয়ে গেলেও, যে উদাহরণটি এটি নির্দেশ করে তা সংশোধন করা হয়নি , এবং এটিতে নির্দেশিত অন্যান্য সমস্ত রেফারেন্স ভেরিয়েবলগুলি (বেনামে শ্রেণীর মতো: $ 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 যেখানে এটি ইনস্ট্যান্ট করা হয়েছিল সেখানে এনক্লোসিংক্লাসের উদাহরণটির একটি রেফারেন্স রাখবে (এটি কেবল একটি উপস্থাপনা, তবে আপনাকে যেতে দেওয়া উচিত):
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);
}
}
এটির মতো, যখন এনক্লোসিংক্লাসের রেফারেন্স ভেরিয়েবলটি 'ভাগ করা' পুনরায় স্বাক্ষরিত হয় এবং থ্রেড # রান () এর কল করার আগে এটি ঘটে, আপনি "অন্যান্য হ্যালো" দু'বার মুদ্রিত দেখতে পাবেন, কারণ এখন এনক্লোসিংক্লাস # 1 # এনকোলেসিং ভেরিয়েবল একটি রেফারেন্স রাখবে যে শ্রেণীর এটি ঘোষিত হয়েছিল তার অবজেক্টে, সুতরাং সেই বস্তুর যে কোনও বৈশিষ্ট্যে পরিবর্তনগুলি এনক্লোজিংক্লাস $ 1 এর উদাহরণগুলিতে দৃশ্যমান হবে।
বিষয় সম্পর্কে আরও তথ্যের জন্য, আপনি এই দুর্দান্ত ব্লগ পোস্টটি দেখতে পাবেন (আমার দ্বারা লিখিত নয়): http://kevinboone.net/java_inner.html