Cloning Object

একটি অবজেক্টের exact কপি আরেকটি অবজেক্টে কপি করাকে Object Cloning বলে। বাকি সব অবজেক্টের মত Cloned অবজেক্টও Heap মেমরিতে Stored হয়। জাভাতে অবজেক্ট ক্লোন করার জন্য যে কয়েকটি way আছে, তার মধ্যে একটি হল- clone()  নামে একটি মেথড ইউজ করা, যেটি কিনা Object ক্লাসের একটি প্রটেক্টেড মেথড।

যে ক্লাসের অবজেক্টের জন্য clone() মেথড কল করব, সে ক্লাসটিকে অবশ্যই Cloneable() ইন্টারফেস ইমপ্লিমেন্ট করতে হবে। না করলে কোড কম্পাইল হবে, কিন্তু রানটাইমে একটি CloneNotSupportedException হবে। Cloneable() ইন্টারফেস ইমপ্লিমেন্ট করার মাধ্যমে আমি ক্লাসটিকে কোন অবজেক্ট ক্লোন করার ability দিচ্ছি।

যেহেতু সব ক্লাসই অবজেক্ট ক্লাসকে extend করে, তাই আমরা যেকোন ক্লাস থেকেই clone() কে কল করতে পারি। কিন্তু যে ক্লাসের অবজেক্টকে ক্লোন করতে চাচ্ছি, সেই ক্লাসটি যদি Cloneable() ইন্টারফেসকে ইমপ্লিমেন্ট না করে তাহলে runtime এ গিয়ে ক্লাসটির ক্লোন করার ability না থাকায় Exception (CloneNotSupportedException) ঘটে।

এবার কোড দেখিঃ

Identity Class:

public class Identity {

	String department;
	String batch;
	int rollNumber;
	
	public Identity(String department, String batch, int rollNumber) {
		
		this.department = department;
		this.batch = batch;
		this.rollNumber = rollNumber;
	}
}

Student Class:

public class Student implements Cloneable {
	
        Identity identity;
	String firstName;
	String lastName ;
	int age;
	
	Student(String firstName, String lastName, int age, Identity identity) {
		
		this.firstName = firstName;
		this.lastName = lastName;
		this.age = age;
		this.identity = identity;
	}
	
	public int getAge() {	
		return age;
	}
	
	public String getFirstName() {
		return firstName;
	}
	
	public String getLastName() {
		return lastName;
	}
	
	public Identity getIdentity() {
		return identity;
	}
	
	public Object clone() throws CloneNotSupportedException {
		return super.clone();
	}
}

Main Class:

public class Main {

	public static void main(String[] args) {
		
		Identity identity = new Identity("CSE", "09", 97);
		Student student1 = new Student("Mukit", "Chowdhury", 27, identity);
		try {
			Student student2= (Student) student1.clone();
			System.out.println("Name: " + student2.getFirstName() + " " + student2.getLastName());
			System.out.println("Batch: " + student2.getIdentity().batch + ", Age: " + student2.age 
					+ ", Department: " + student2.getIdentity().department + ", RollNumber: "
					+ student2.getIdentity().rollNumber);
			
                        student1.firstName = "Rakib";
			student1.identity.department = "EEE";
			student1.identity.rollNumber = 56;
                        student1.age = 30;
                        System.out.println("Name: " + student2.getFirstName() + " " + student2.getLastName()); 
			System.out.println("Batch: " + student2.getIdentity().batch + ", Age: " + student2.age 
                                        + ", Department: " + student2.getIdentity().department + ", RollNumber: "
                                        + student2.getIdentity().rollNumber);
		} catch (CloneNotSupportedException e) {
			e.printStackTrace();
		}
	}
}

Identity ক্লাসের একটি রেফারেন্স Student ক্লাসের মেম্বার ভ্যারিয়েবল হিসেবে ডিক্লেয়ার করা হয়েছে। আর Main ক্লাসের main মেথডে Student ক্লাসের একটি অবজেক্ট বানিয়ে সেই অবজেক্টটিকে ক্লোন করা হয়েছে।

এখানে আমি যে ক্লোনটা করেছি, এটাকে বলা হয় Shallow Cloning. এই ক্লোনিং এ মূল অবজেক্টের কোন member variable যদি অন্য আরেকটি অবজেক্টের রেফারেন্স হয়, সেক্ষেত্রে শুধু রেফারেন্স কপি হয়। ফলে মূল অবজেক্টের (উপরের example এ student1) ঐ রেফারেন্স(এক্ষেত্রে Identity) ধরে তার কোন member variable চেইঞ্জ করলে তার affect ক্লোনড অবজেক্টেও (উদাহরণে student2) পড়ে।

আর মেম্বার ভ্যারিয়েবল যদি primitive data type হয় সেক্ষেত্রে ভ্যারিয়েবলের ভ্যালুটি ক্লোনড অবজেক্টের ঐ মেম্বার ভ্যারিয়েবলের ভ্যালু হিসেবে কপি করে রাখে।

এই যে মেম্বার ভ্যারিয়েবল primitive হলে এক রকম behavior আর রেফারেন্স হলে 
আরেক রকম, এর কারণ কি? এটার উত্তর একটু পর দিচ্ছি!

আরেক ধরণের ক্লোনিং আছে জাভাতে, যেটাকে বলা হয় Deep Cloning. এই ক্লোনিং এ মুল অবজেক্ট এবং ক্লোনড অবজেক্ট – দু’টিতেই সব মেম্বার ভ্যারিয়েবলই independent থাকে। অর্থাৎ, আমি এই দুই অবজেক্টের যেটিতেই চেইঞ্জ করিনা কেন, অপরটিতে কোন affect থাকবে না।

আচ্ছা, এবার আগের প্রশ্নের উত্তরটি দেই! Shallow cloning এ প্রতিটি অবজেক্ট আরেকটি অবজেক্টে বিট-বাই-বিট কপি হয়। তাই সে মেম্বার ভ্যারিয়েবলের যে ভ্যালু পায় সেটিই কপি করে। এখন রেফারেন্স টাইপের জন্য ভ্যালু তো থাকে আসলে একটা reference of address। তাই যখন বিট-বাই-বিট কপি হয়, তখন এই reference of address টিও ক্লোনড অবজেক্টের রেফারেন্স হিসেবে কপি হয়। ফলে দু’টি রেফারেন্সই এখন একই address কে রেফার করছে। যার কারণে এই দুই অবজেক্টের যেকোন একটিতে ঐ মেম্বার ভ্যারিয়েবল রেফারেন্স চেইঞ্জ করলে আরেকটিতেও সেইম চেইঞ্জ হয়ে যায়।

এবার আরেকটি প্রশ্ন! উপরের কোডগুলো যদি রান করে দেখি। দেখব যে, student1 এর firstName চেইঞ্জ করলেও সেই চেইঞ্জটা student2 এর firstName এ পড়েনি! কিন্তু firstName তো String টাইপ, অর্থাৎ primitive না! তাহলে চেইঞ্জ হল না কেন? এটা চিন্তা করে বের কর! 😀

2 thoughts on “Cloning Object

  1. Cloneable() ইন্টারফেস ইমপ্লিমেন্ট করার মাধ্যমে আমি ক্লাসটিকে কোন অবজেক্ট ক্লোন করার ability দিচ্ছি।

    এই কথাটা ঠিক না। ইন্টারফেস ইম্পলিমেন্ট এর মাধ্যমে কোন এবিলিটি যোগ হচ্ছে না। এইটা একটা পারমিশন বা লিগালিটি দিচ্ছি বড়জোর। এই ইন্টারফেসের ভিতরে কিছুই নাই, খালি। সো বুঝাই যাচ্ছে এর করার কিছু নাই, টাইপ ডিফাইন করা ছাড়া।

    নীচে জাভা ডক এর কয়েকটা লাইন দিলাম।

    A class implements the Cloneable interface to indicate to the Object.clone() method that it is legal for that method to make a field-for-field copy of instances of that class.

    https://docs.oracle.com/javase/7/docs/api/java/lang/Cloneable.html

    1. আপনি যেটাকে “পারমিশন” বলছেন, আমি সেটাকেই “এবিলিটি” বলছি। আর জাভা ডকে “লিগাল” ইউজ করা হয়েছে। একটা ইন্টারফেসের মধ্যে “নরমালি” শুধু মেথড সিগনেচারই থাকে। তারপরও সে যেভাবে আরেকটা ক্লাসকে ঐ মেথড ইউজ করার “পারমিশন” দেয়, সেভাবেই আমি “এবিলিটি” দেয়ার কথা বলেছি। আমি এবিলিটি কিংবা আপনি পারমিশন লিখাতে – কোনটিই জাভা ডকের লিখাটির বিরুদ্ধে যায় না।

      এখানে পারমিশন, লিগালিটি কিংবা এবিলিটি – যাই ইউজ করেন না কেন, অর্থ একই দাঁড়াচ্ছে। আপনি যদি রিয়েল লাইফের সাথে কম্পেয়ার করেন, যে ক্লাসটা Cloneable কে ইমপ্লিমেন্ট করছে, তার এখন ability হয়েছে Clone করার। যদি Comparable কে ইমপ্লিমেন্ট করছে, তার এখন ability হয়েছে Compare করার।

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s