Serializable
اس کا کام کیا، اور پورے عمل کے خودکار نفاذ کے بارے میں کیا پسند نہیں ہے؟ اور جن مثالوں کو ہم نے دیکھا وہ بھی غیر پیچیدہ تھیں۔ تو کیا مسئلہ ہے؟ بنیادی طور پر ایک جیسے کاموں کے لیے ہمیں ایک اور انٹرفیس کی ضرورت کیوں ہے؟ حقیقت یہ ہے کہ اس Serializable
میں کئی خامیاں ہیں۔ ہم ان میں سے کچھ کی فہرست دیتے ہیں:
-
کارکردگی۔ انٹرفیس
Serializable
کے بہت سے فوائد ہیں، لیکن اعلی کارکردگی واضح طور پر ان میں سے ایک نہیں ہے۔سب سے پہلے،
Serializable
کا داخلی نفاذ بڑی مقدار میں سروس کی معلومات اور ہر قسم کا عارضی ڈیٹا تیار کرتا ہے۔دوسرا،
Serializable
Reflection API پر انحصار کرتا ہے (آپ کو ابھی اس پر گہرا غوطہ لگانے کی ضرورت نہیں ہے؛ اگر آپ دلچسپی رکھتے ہیں تو آپ اپنی فرصت میں مزید پڑھ سکتے ہیں)۔ یہ چیز آپ کو جاوا میں بظاہر ناممکن کام کرنے دیتی ہے: مثال کے طور پر، پرائیویٹ فیلڈز کی اقدار کو تبدیل کریں۔ CodeGym میں Reflection API کے بارے میں ایک بہترین مضمون ہے ۔ آپ وہاں اس کے بارے میں پڑھ سکتے ہیں۔ -
لچک
Serializable
جب ہم انٹرفیس استعمال کرتے ہیں تو ہم سیریلائزیشن-ڈی سیریلائزیشن کے عمل کو کنٹرول نہیں کرتے ہیں ۔ایک طرف، یہ بہت آسان ہے، کیونکہ اگر ہم خاص طور پر کارکردگی کے بارے میں فکر مند نہیں ہیں، تو یہ اچھا لگتا ہے کہ کوڈ نہیں لکھنا پڑے گا۔ لیکن کیا ہوگا اگر ہمیں واقعی سیریلائزیشن منطق میں اپنی کچھ خصوصیات (ہم ذیل میں ایک مثال فراہم کریں گے) شامل کرنے کی ضرورت ہے؟
بنیادی طور پر، ہمیں صرف اس عمل کو کنٹرول کرنا ہے
transient
کچھ ڈیٹا کو خارج کرنے کا کلیدی لفظ ہے۔ یہی ہے. یہ ہمارا پورا ٹول باکس ہے :/ -
سیکورٹی. یہ آئٹم کچھ حصہ پچھلی آئٹم سے ماخوذ ہے۔
ہم نے پہلے اس کے بارے میں سوچنے میں زیادہ وقت نہیں گزارا، لیکن اگر آپ کی کلاس میں کچھ معلومات دوسروں کی آنکھوں اور کانوں کے لیے نہیں ہیں تو کیا ہوگا؟ ایک سادہ مثال پاس ورڈ یا دیگر ذاتی صارف کا ڈیٹا ہے، جو آج کی دنیا میں قوانین کے ایک گروپ کے ذریعے چلایا جاتا ہے۔
اگر ہم استعمال کرتے ہیں
Serializable
تو ہم واقعی اس کے بارے میں کچھ نہیں کر سکتے۔ ہم ہر چیز کو سیریلائز کرتے ہیں جیسا کہ یہ ہے۔لیکن اگر ہم اسے صحیح طریقے سے کرتے ہیں، تو ہمیں اس قسم کے ڈیٹا کو فائل پر لکھنے یا نیٹ ورک پر بھیجنے سے پہلے انکرپٹ کرنا چاہیے۔ لیکن
Serializable
یہ ممکن نہیں بناتا۔
Externalizable
انٹرفیس استعمال کریں گے تو کلاس کیسی نظر آئے گی۔
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
public class UserInfo implements Externalizable {
private String firstName;
private String lastName;
private String superSecretInformation;
private static final long SERIAL_VERSION_UID = 1L;
// ...constructor, getters, setters, toString()...
@Override
public void writeExternal(ObjectOutput out) throws IOException {
}
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
}
}
جیسا کہ آپ دیکھ سکتے ہیں، ہمارے پاس اہم تبدیلیاں ہیں! اہم ایک واضح ہے: Externalizable
انٹرفیس کو لاگو کرتے وقت، آپ کو دو مطلوبہ طریقوں کو لاگو کرنا ہوگا: writeExternal()
اور readExternal()
. جیسا کہ ہم نے پہلے کہا، سیریلائزیشن اور ڈی سیریلائزیشن کی ذمہ داری پروگرامر پر عائد ہوگی۔ لیکن اب آپ عمل پر کوئی کنٹرول نہ ہونے کا مسئلہ حل کر سکتے ہیں! پورا عمل آپ کے ذریعہ براہ راست پروگرام کیا گیا ہے۔ قدرتی طور پر، یہ ایک بہت زیادہ لچکدار طریقہ کار کی اجازت دیتا ہے. مزید برآں، سیکورٹی کا مسئلہ حل ہو گیا ہے۔ جیسا کہ آپ دیکھ سکتے ہیں، ہماری کلاس میں ایک ذاتی ڈیٹا فیلڈ ہے جسے غیر خفیہ کردہ ذخیرہ نہیں کیا جا سکتا۔ اب ہم آسانی سے کوڈ لکھ سکتے ہیں جو اس رکاوٹ کو پورا کرتا ہے۔ مثال کے طور پر، ہم اپنی کلاس میں حساس ڈیٹا کو انکرپٹ اور ڈکرپٹ کرنے کے لیے دو آسان نجی طریقے شامل کر سکتے ہیں۔ ہم فائل میں ڈیٹا لکھیں گے اور اسے فائل سے انکرپٹڈ شکل میں پڑھیں گے۔ بقیہ ڈیٹا اسی طرح لکھا اور پڑھا جائے گا :) اس کے نتیجے میں ہماری کلاس کچھ اس طرح نظر آتی ہے:
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.Base64;
public class UserInfo implements Externalizable {
private String firstName;
private String lastName;
private String superSecretInformation;
private static final long serialVersionUID = 1L;
public UserInfo() {
}
public UserInfo(String firstName, String lastName, String superSecretInformation) {
this.firstName = firstName;
this.lastName = lastName;
this.superSecretInformation = superSecretInformation;
}
@Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeObject(this.getFirstName());
out.writeObject(this.getLastName());
out.writeObject(this.encryptString(this.getSuperSecretInformation()));
}
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
firstName = (String) in.readObject();
lastName = (String) in.readObject();
superSecretInformation = this.decryptString((String) in.readObject());
}
private String encryptString(String data) {
String encryptedData = Base64.getEncoder().encodeToString(data.getBytes());
System.out.println(encryptedData);
return encryptedData;
}
private String decryptString(String data) {
String decrypted = new String(Base64.getDecoder().decode(data));
System.out.println(decrypted);
return decrypted;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public String getSuperSecretInformation() {
return superSecretInformation;
}
}
ہم نے دو طریقے نافذ کیے جو ایک جیسے ObjectOutput
اور ObjectInput
پیرامیٹرز کا استعمال کرتے ہیں جو ہم نے پہلے ہی سبق میں حاصل کیے تھے Serializable
۔ صحیح وقت پر، ہم مطلوبہ ڈیٹا کو انکرپٹ یا ڈکرپٹ کرتے ہیں، اور ہم اپنے اعتراض کو سیریلائز کرنے کے لیے انکرپٹڈ ڈیٹا کا استعمال کرتے ہیں۔ آئیے دیکھتے ہیں کہ یہ عملی طور پر کیسا لگتا ہے:
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException, ClassNotFoundException {
FileOutputStream fileOutputStream = new FileOutputStream("C:\\Users\\Username\\Desktop\\save.ser");
ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
UserInfo userInfo = new UserInfo("Paul", "Piper", "Paul Piper's passport data");
objectOutputStream.writeObject(userInfo);
objectOutputStream.close();
}
}
encryptString()
اور طریقوں میں decryptString()
، ہم نے خاص طور پر اس فارم کی تصدیق کے لیے کنسول آؤٹ پٹ شامل کیا جس میں خفیہ ڈیٹا لکھا اور پڑھا جائے گا۔ مندرجہ بالا کوڈ نے درج ذیل لائن کو دکھایا: SXZhbiBJdmFub3YncyBwYXNzcG9ydCBkYXRh خفیہ کاری کامیاب ہو گئی! فائل کے مکمل مواد اس طرح نظر آتے ہیں: ¬н sr UserInfoГ!}ҐџC‚ћ xpt Ivant Ivanovt $SXZhbiBJdmFub3YncyBwYXNzcG9ydCBkYXRhx اب آئیے اپنی ڈیسیریلائزیشن منطق کو استعمال کرنے کی کوشش کریں۔
public class Main {
public static void main(String[] args) throws IOException, ClassNotFoundException {
FileInputStream fileInputStream = new FileInputStream("C:\\Users\\Username\\Desktop\\save.ser");
ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
UserInfo userInfo = (UserInfo) objectInputStream.readObject();
System.out.println(userInfo);
objectInputStream.close();
}
}
ٹھیک ہے، یہاں کچھ بھی پیچیدہ نہیں لگتا ہے۔ یہ کام کرنا چاہئے! ہم اسے چلاتے ہیں اور حاصل کرتے ہیں... "مین" تھریڈ میں استثناء java.io.InvalidClassException: UserInfo; کوئی درست کنسٹرکٹر نہیں افوہ! :( بظاہر، یہ اتنا آسان نہیں ہے! ڈی سیریلائزیشن میکانزم نے ایک استثناء دیا اور ہم سے ڈیفالٹ کنسٹرکٹر بنانے کا مطالبہ کیا۔ مجھے حیرت ہے کہ کیوں؟ کے ساتھ، Serializable
ہم بغیر ایک کے گزر گئے... :/ یہاں ہمیں ایک اور اہم بات کا سامنا کرنا پڑا۔ کے درمیان فرق Serializable
اور جھوٹ نہ صرف پروگرامر کی 'توسیع شدہ Externalizable
' رسائی اور عمل کو زیادہ لچکدار طریقے سے کنٹرول کرنے کی صلاحیت میں ہے، بلکہ خود عمل میں بھی ہےSerializable
۔ پھر اقدار کو اسٹریم سے پڑھا جاتا ہے اور آبجیکٹ کے فیلڈز کو سیٹ کرنے کے لیے استعمال کیا جاتا ہے۔ اگر ہم استعمال کرتے ہیں تو Serializable
آبجیکٹ کے کنسٹرکٹر کو نہیں کہا جاتا! تمام کام عکاسی کے ذریعے ہوتا ہے (ریفلیکشن API، جس کا ہم نے مختصراً پچھلے سبق میں ذکر کیا ہے) Externalizable
۔ ڈی سیریلائزیشن میکانزم مختلف ہے۔ پہلے سے طے شدہ کنسٹرکٹر کو پہلے کہا جاتا ہے۔ اس کے بعد ہی تخلیق کردہ UserInfo
آبجیکٹ کا readExternal()
طریقہ کہا جاتا ہے۔ یہ آبجیکٹ کے فیلڈز کو ترتیب دینے کا ذمہ دار ہے۔ اسی وجہ سے انٹرفیس کو نافذ کرنے والی کسی بھی کلاس Externalizable
کے پاس ڈیفالٹ کنسٹرکٹر ہونا ضروری ہے ۔ آئیے ایک کو اپنی UserInfo
کلاس میں شامل کریں اور کوڈ کو دوبارہ چلائیں:
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException, ClassNotFoundException {
FileInputStream fileInputStream = new FileInputStream("C:\\Users\\Username\\Desktop\\save.ser");
ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
UserInfo userInfo = (UserInfo) objectInputStream.readObject();
System.out.println(userInfo);
objectInputStream.close();
}
}
کنسول آؤٹ پٹ: پال پائپر کا پاسپورٹ ڈیٹا UserInfo \ firstName = 'Paul', lastName = 'Piper', superSecretInformation = 'Paul Piper's passport data' } اب یہ بالکل مختلف ہے! سب سے پہلے، خفیہ معلومات کے ساتھ ڈکرپٹڈ سٹرنگ کنسول پر ظاہر کی گئی تھی۔ اس کے بعد ہم نے فائل سے جس چیز کو بازیافت کیا اسے سٹرنگ کے طور پر دکھایا گیا! لہذا ہم نے کامیابی کے ساتھ تمام مسائل کو حل کر لیا ہے :) سیریلائزیشن اور ڈی سیریلائزیشن کا موضوع آسان لگتا ہے، لیکن جیسا کہ آپ دیکھ سکتے ہیں، اسباق طویل ہو چکے ہیں۔ اور بہت کچھ ہے جس کا ہم نے احاطہ نہیں کیا ہے! ان میں سے ہر ایک انٹرفیس کو استعمال کرتے وقت ابھی بھی بہت سی باریکیاں شامل ہیں۔ لیکن ضرورت سے زیادہ نئی معلومات سے آپ کے دماغ کو پھٹنے سے بچنے کے لیے، میں مختصراً چند اور اہم نکات کی فہرست دوں گا اور آپ کو اضافی پڑھنے کے لنکس دوں گا۔ تو، آپ کو اور کیا جاننے کی ضرورت ہے؟ سب سے پہلے ، سیریلائزیشن کے دوران ( قطع نظر اس کے کہ آپ استعمال کر رہے ہیں Serializable
یا Externalizable
)، static
متغیرات پر توجہ دیں۔ جب آپ Serializable
. static
لیکن جب آپ استعمال کرتے ہیں Externalizable
، تو آپ خود اس عمل کو کنٹرول کرتے ہیں، لہذا تکنیکی طور پر آپ انہیں سیریلائز کر سکتے ہیں۔ لیکن، ہم اس کی سفارش نہیں کرتے ہیں، کیونکہ ایسا کرنے سے بہت سے باریک کیڑے پیدا ہونے کا امکان ہے۔ دوسرا ، آپ کو موڈیفائر کے ساتھ متغیرات پر بھی توجہ دینی چاہیے final
۔ جب آپ استعمال کرتے ہیں Serializable
، تو وہ معمول کے مطابق سیریلائز اور ڈی سیریلائز ہوتے ہیں، لیکن جب آپ استعمال کرتے ہیں ، تو متغیر Externalizable
کو ڈی سیریلائز کرنا ناممکن ہےfinal
! وجہ سادہ ہے: final
جب ڈیفالٹ کنسٹرکٹر کو بلایا جاتا ہے تو تمام فیلڈز کو شروع کیا جاتا ہے - اس کے بعد، ان کی قدر کو تبدیل نہیں کیا جا سکتا۔ لہذا، فیلڈز والی اشیاء کو سیریلائز کرنے کے لیے final
، فراہم کردہ معیاری سیریلائزیشن کا استعمال کریں Serializable
۔ تیسرا ، جب آپ وراثت کا استعمال کرتے ہیں، تمام نسلی طبقے جو کچھ Externalizable
کلاس کے وارث ہوتے ہیں ان کے پاس ڈیفالٹ کنسٹرکٹرز بھی ہونے چاہئیں۔ سیریلائزیشن میکانزم کے بارے میں اچھے مضمون کا لنک یہ ہے:
اگلے وقت تک! :)
GO TO FULL VERSION