CodeGym /جاوا بلاگ /Random-UR /جاوا میں بیرونی قابل انٹرفیس
John Squirrels
سطح
San Francisco

جاوا میں بیرونی قابل انٹرفیس

گروپ میں شائع ہوا۔
ہائے! آج ہم جاوا آبجیکٹ کے سیریلائزیشن اور ڈی سیریلائزیشن کو جاننا جاری رکھیں گے ۔ پچھلے سبق میں، ہم نے سیریلائز ایبل مارکر انٹرفیس کو جانا ، اس کے استعمال کی مثالوں کا جائزہ لیا، اور یہ بھی سیکھا کہ آپ سیریلائزیشن کے عمل کو کنٹرول کرنے کے لیے عارضی کلیدی لفظ کا استعمال کیسے کر سکتے ہیں۔ ٹھیک ہے، یہ کہنا کہ ہم 'عمل کو کنٹرول کرتے ہیں' اس کو بڑھاوا دے رہا ہے۔ ہمارے پاس ایک مطلوبہ لفظ، ایک ورژن شناخت کنندہ ہے، اور یہ اس کے بارے میں ہے۔ باقی عمل جاوا کے اندر پوشیدہ ہے، اور ہم اس تک رسائی حاصل نہیں کر سکتے۔ بے شک، سہولت کے لحاظ سے، یہ اچھا ہے. لیکن ایک پروگرامر کو صرف اس کے اپنے آرام سے رہنمائی نہیں کرنی چاہئے، ٹھیک ہے؟ :) آپ کو غور کرنے کی ضرورت ہے کہ دیگر عوامل ہیں. یہی وجہ ہے کہ جاوا میں سیریلائزیشن ڈی سیریلائزیشن کے لیے سیریلائز ایبل واحد طریقہ کار نہیں ہے۔ آج ہم Externalizable انٹرفیس سے واقف ہوں گے ۔ لیکن اس سے پہلے کہ ہم اس کا مطالعہ شروع کریں، آپ کے پاس ایک معقول سوال ہو سکتا ہے: ہمیں ایک اور طریقہ کار کی ضرورت کیوں ہے؟ Serializableاس کا کام کیا، اور پورے عمل کے خودکار نفاذ کے بارے میں کیا پسند نہیں ہے؟ اور جن مثالوں کو ہم نے دیکھا وہ بھی غیر پیچیدہ تھیں۔ تو کیا مسئلہ ہے؟ بنیادی طور پر ایک جیسے کاموں کے لیے ہمیں ایک اور انٹرفیس کی ضرورت کیوں ہے؟ حقیقت یہ ہے کہ اس Serializableمیں کئی خامیاں ہیں۔ ہم ان میں سے کچھ کی فہرست دیتے ہیں:
  1. کارکردگی۔ انٹرفیس Serializableکے بہت سے فوائد ہیں، لیکن اعلی کارکردگی واضح طور پر ان میں سے ایک نہیں ہے۔

    ایکسٹرنلائز ایبل انٹرفیس کا تعارف - 2

    سب سے پہلے، Serializable کا داخلی نفاذ بڑی مقدار میں سروس کی معلومات اور ہر قسم کا عارضی ڈیٹا تیار کرتا ہے۔

    دوسرا، Serializable Reflection API پر انحصار کرتا ہے (آپ کو ابھی اس پر گہرا غوطہ لگانے کی ضرورت نہیں ہے؛ اگر آپ دلچسپی رکھتے ہیں تو آپ اپنی فرصت میں مزید پڑھ سکتے ہیں)۔ یہ چیز آپ کو جاوا میں بظاہر ناممکن کام کرنے دیتی ہے: مثال کے طور پر، پرائیویٹ فیلڈز کی اقدار کو تبدیل کریں۔ CodeGym میں Reflection API کے بارے میں ایک بہترین مضمون ہے ۔ آپ وہاں اس کے بارے میں پڑھ سکتے ہیں۔

  2. لچک Serializableجب ہم انٹرفیس استعمال کرتے ہیں تو ہم سیریلائزیشن-ڈی سیریلائزیشن کے عمل کو کنٹرول نہیں کرتے ہیں ۔

    ایک طرف، یہ بہت آسان ہے، کیونکہ اگر ہم خاص طور پر کارکردگی کے بارے میں فکر مند نہیں ہیں، تو یہ اچھا لگتا ہے کہ کوڈ نہیں لکھنا پڑے گا۔ لیکن کیا ہوگا اگر ہمیں واقعی سیریلائزیشن منطق میں اپنی کچھ خصوصیات (ہم ذیل میں ایک مثال فراہم کریں گے) شامل کرنے کی ضرورت ہے؟

    بنیادی طور پر، ہمیں صرف اس عمل کو کنٹرول کرنا ہے transientکچھ ڈیٹا کو خارج کرنے کا کلیدی لفظ ہے۔ یہی ہے. یہ ہمارا پورا ٹول باکس ہے :/

  3. سیکورٹی. یہ آئٹم کچھ حصہ پچھلی آئٹم سے ماخوذ ہے۔

    ہم نے پہلے اس کے بارے میں سوچنے میں زیادہ وقت نہیں گزارا، لیکن اگر آپ کی کلاس میں کچھ معلومات دوسروں کی آنکھوں اور کانوں کے لیے نہیں ہیں تو کیا ہوگا؟ ایک سادہ مثال پاس ورڈ یا دیگر ذاتی صارف کا ڈیٹا ہے، جو آج کی دنیا میں قوانین کے ایک گروپ کے ذریعے چلایا جاتا ہے۔

    اگر ہم استعمال کرتے ہیں Serializableتو ہم واقعی اس کے بارے میں کچھ نہیں کر سکتے۔ ہم ہر چیز کو سیریلائز کرتے ہیں جیسا کہ یہ ہے۔

    لیکن اگر ہم اسے صحیح طریقے سے کرتے ہیں، تو ہمیں اس قسم کے ڈیٹا کو فائل پر لکھنے یا نیٹ ورک پر بھیجنے سے پہلے انکرپٹ کرنا چاہیے۔ لیکن Serializableیہ ممکن نہیں بناتا۔

ایکسٹرنلائز ایبل انٹرفیس کا تعارف - 3ٹھیک ہے، آئیے آخر کار دیکھتے ہیں کہ اگر ہم 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; کوئی درست کنسٹرکٹر نہیں ایکسٹرنلائز ایبل انٹرفیس کا تعارف - 4 افوہ! :( بظاہر، یہ اتنا آسان نہیں ہے! ڈی سیریلائزیشن میکانزم نے ایک استثناء دیا اور ہم سے ڈیفالٹ کنسٹرکٹر بنانے کا مطالبہ کیا۔ مجھے حیرت ہے کہ کیوں؟ کے ساتھ، 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یا Externalizablestaticمتغیرات پر توجہ دیں۔ جب آپ Serializable. staticلیکن جب آپ استعمال کرتے ہیں Externalizable، تو آپ خود اس عمل کو کنٹرول کرتے ہیں، لہذا تکنیکی طور پر آپ انہیں سیریلائز کر سکتے ہیں۔ لیکن، ہم اس کی سفارش نہیں کرتے ہیں، کیونکہ ایسا کرنے سے بہت سے باریک کیڑے پیدا ہونے کا امکان ہے۔ دوسرا ، آپ کو موڈیفائر کے ساتھ متغیرات پر بھی توجہ دینی چاہیے final۔ جب آپ استعمال کرتے ہیں Serializable، تو وہ معمول کے مطابق سیریلائز اور ڈی سیریلائز ہوتے ہیں، لیکن جب آپ استعمال کرتے ہیں ، تو متغیر Externalizableکو ڈی سیریلائز کرنا ناممکن ہےfinal ! وجہ سادہ ہے: finalجب ڈیفالٹ کنسٹرکٹر کو بلایا جاتا ہے تو تمام فیلڈز کو شروع کیا جاتا ہے - اس کے بعد، ان کی قدر کو تبدیل نہیں کیا جا سکتا۔ لہذا، فیلڈز والی اشیاء کو سیریلائز کرنے کے لیے final، فراہم کردہ معیاری سیریلائزیشن کا استعمال کریں Serializable۔ تیسرا ، جب آپ وراثت کا استعمال کرتے ہیں، تمام نسلی طبقے جو کچھ Externalizableکلاس کے وارث ہوتے ہیں ان کے پاس ڈیفالٹ کنسٹرکٹرز بھی ہونے چاہئیں۔ سیریلائزیشن میکانزم کے بارے میں اچھے مضمون کا لنک یہ ہے: اگلے وقت تک! :)
تبصرے
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION