Java में ऑब्जेक्ट सीरियलाइज़ेशन: बुनियादी से उन्नत तकनीकों तक
सीरियलाइज़ेशन किसी ऑब्जेक्ट की स्थिति (state) को बाइट स्ट्रीम में बदलने की प्रक्रिया है, ताकि उसे फ़ाइल, डेटाबेस में सेव किया जा सके या नेटवर्क पर भेजा जा सके। इसका उल्टा प्रोसेस डीसीरियलाइज़ेशन (Deserialization) कहलाता है, जो बाइट स्ट्रीम से ऑब्जेक्ट को पुनर्स्थापित करता है। Java में यह तंत्र प्लेटफ़ॉर्म में बिल्ट-इन है और डिस्ट्रीब्यूटेड सिस्टम, कैशिंग और वेब एप्लिकेशन में व्यापक रूप से उपयोग होता है। इस लेख में हम जानेंगे कि सीरियलाइज़ेशन कैसे काम करता है, कौन से इंटरफ़ेस और क्लास शामिल हैं, और कस्टम सीरियलाइज़ेशन को सही तरीके से कैसे लागू करें।
बुनियादी बातें: Serializable इंटरफ़ेस
किसी ऑब्जेक्ट को सीरियलाइज़ करने के लिए, उसकी क्लास को मार्कर इंटरफ़ेस java.io.Serializable को इम्प्लीमेंट करना होता है। इस इंटरफ़ेस में कोई मेथड नहीं है - यह सिर्फ वर्चुअल मशीन को बताता है कि इस ऑब्जेक्ट को सीरियलाइज़ करने की अनुमति है।
import java.io.Serializable;
public class User implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "User{name='" + name + "', age=" + age + "}";
}
}
serialVersionUID फ़ील्ड क्लास के वर्जन की एक यूनिक आइडेंटिफ़ायर है। अगर इसे स्पष्ट रूप से घोषित नहीं किया जाता है, तो JVM इसे ऑटोमैटिकली कैलकुलेट करता है, लेकिन इससे डीसीरियलाइज़ेशन के दौरान InvalidClassException आ सकता है, अगर क्लास बदल गई हो। हमेशा इसे मैन्युअली सेट करने की सलाह दी जाती है।
सीरियलाइज़ेशन और डीसीरियलाइज़ेशन की प्रक्रिया
ऑब्जेक्ट को स्ट्रीम में लिखने के लिए ObjectOutputStream और पढ़ने के लिए ObjectInputStream का उपयोग किया जाता है। आइए एक बुनियादी उदाहरण देखें:
import java.io.*;
public class SerializationDemo {
public static void main(String[] args) {
User user = new User("राहुल", 30);
// सीरियलाइज़ेशन
try (FileOutputStream fos = new FileOutputStream("user.ser");
ObjectOutputStream oos = new ObjectOutputStream(fos)) {
oos.writeObject(user);
System.out.println("ऑब्जेक्ट सीरियलाइज़ किया गया: " + user);
} catch (IOException e) {
e.printStackTrace();
}
// डीसीरियलाइज़ेशन
try (FileInputStream fis = new FileInputStream("user.ser");
ObjectInputStream ois = new ObjectInputStream(fis)) {
User restoredUser = (User) ois.readObject();
System.out.println("ऑब्जेक्ट पुनर्स्थापित किया गया: " + restoredUser);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
डीसीरियलाइज़ेशन के दौरान ऑब्जेक्ट का कंस्ट्रक्टर कॉल नहीं होता - स्थिति सीधे स्ट्रीम से पुनर्स्थापित की जाती है। यह new के माध्यम से सामान्य ऑब्जेक्ट निर्माण से एक महत्वपूर्ण अंतर है।
transient कीवर्ड
कभी-कभी कुछ फ़ील्ड्स को सीरियलाइज़ेशन से बाहर रखना आवश्यक होता है, जैसे पासवर्ड या अस्थायी गणनाएँ। इसके लिए transient मॉडिफ़ायर का उपयोग किया जाता है। इससे चिह्नित फ़ील्ड्स को सीरियलाइज़ेशन के दौरान डिफ़ॉल्ट मान (0, null, false) मिलते हैं।
public class UserWithPassword implements Serializable {
private static final long serialVersionUID = 1L;
private String login;
private transient String password; // सीरियलाइज़ नहीं होगा
public UserWithPassword(String login, String password) {
this.login = login;
this.password = password;
}
@Override
public String toString() {
return "User{login='" + login + "', password='" + password + "'}";
}
}
डीसीरियलाइज़ेशन के बाद password फ़ील्ड null होगा। यह सुरक्षा के लिए सुविधाजनक है, लेकिन इसे पुनर्स्थापित करने के लिए अतिरिक्त लॉजिक की आवश्यकता होती है।
कस्टम सीरियलाइज़ेशन: writeObject और readObject मेथड
अगर डिफ़ॉल्ट व्यवहार संतोषजनक नहीं है, तो प्राइवेट मेथड writeObject(ObjectOutputStream oos) और readObject(ObjectInputStream ois) को ओवरराइड किया जा सकता है।