CodeGym /Java Blog /यादृच्छिक /जावा मधील बाह्य इंटरफेस
John Squirrels
पातळी 41
San Francisco

जावा मधील बाह्य इंटरफेस

यादृच्छिक या ग्रुपमध्ये प्रकाशित केले
हाय! आज आपण जावा ऑब्जेक्ट्सचे सीरियलायझेशन आणि डीसीरियलायझेशन जाणून घेणे सुरू ठेवू . शेवटच्या धड्यात, आम्हाला सिरियलायझ करण्यायोग्य मार्कर इंटरफेस माहित झाला, त्याच्या वापराच्या उदाहरणांचे पुनरावलोकन केले आणि आपण क्रमिकीकरण प्रक्रिया नियंत्रित करण्यासाठी क्षणिक कीवर्ड कसे वापरू शकता हे देखील शिकलो. बरं, आम्ही 'प्रक्रियेवर नियंत्रण ठेवतो' असे म्हणणे कदाचित त्याचा अतिरेक करत असेल. आमच्याकडे एक कीवर्ड आहे, एक आवृत्ती अभिज्ञापक आहे, आणि ते त्याबद्दल आहे. उर्वरित प्रक्रिया Java मध्ये लपलेली आहे आणि आम्ही त्यात प्रवेश करू शकत नाही. अर्थात, सोयीच्या दृष्टीने हे चांगले आहे. परंतु प्रोग्रामरला केवळ त्याच्या स्वतःच्या सोयीनुसार मार्गदर्शन केले जाऊ नये, बरोबर? :) आपण विचार करणे आवश्यक आहे की इतर घटक आहेत. म्हणूनच सीरिअलायझेबलJava मधील सीरियलायझेशन-डिसिरियलायझेशनसाठी एकमेव यंत्रणा नाही. आज आपण Externalizable इंटरफेसशी परिचित होऊ . परंतु आम्ही त्याचा अभ्यास सुरू करण्यापूर्वी, तुमच्याकडे एक वाजवी प्रश्न असू शकतो: आम्हाला दुसरी यंत्रणा का आवश्यक आहे? Serializableत्याचे कार्य केले, आणि संपूर्ण प्रक्रियेच्या स्वयंचलित अंमलबजावणीबद्दल काय आवडत नाही? आणि आम्ही पाहिलेली उदाहरणे देखील जटिल होती. मग अडचण काय आहे? मूलत: समान कार्यांसाठी आम्हाला दुसर्‍या इंटरफेसची आवश्यकता का आहे? वस्तुस्थिती अशी आहे की त्यात Serializableअनेक कमतरता आहेत. आम्ही त्यापैकी काही सूचीबद्ध करतो:
  1. कामगिरी. इंटरफेसमध्ये Serializableअनेक फायदे आहेत, परंतु उच्च कार्यक्षमता स्पष्टपणे त्यापैकी एक नाही.

    एक्सटर्नलाइझ करण्यायोग्य इंटरफेस सादर करत आहे - 2

    प्रथम, Serializable अंतर्गत अंमलबजावणी मोठ्या प्रमाणात सेवा माहिती आणि सर्व प्रकारचा तात्पुरता डेटा व्युत्पन्न करते.

    दुसरे, Serializable रिफ्लेक्शन एपीआयवर अवलंबून आहे (तुम्हाला आत्ता यावर खोलवर जाण्याची गरज नाही; तुम्हाला स्वारस्य असल्यास, तुम्ही तुमच्या आरामात अधिक वाचू शकता). ही गोष्ट तुम्हाला Java मध्ये अशक्य वाटणाऱ्या गोष्टी करू देते: उदाहरणार्थ, खाजगी फील्डची मूल्ये बदला. 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डिसिरियलायझेशन मेकॅनिझममध्ये . वापरतानाExternalizableSerializable, मेमरी फक्त ऑब्जेक्टसाठी वाटप केली जाते, आणि नंतर प्रवाहातून मूल्ये वाचली जातात आणि ऑब्जेक्टची फील्ड सेट करण्यासाठी वापरली जातात. आपण वापरल्यास 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 = 'पॉल पायपरचा पासपोर्ट डेटा' } आता ते पूर्णपणे वेगळे आहे! प्रथम, गुप्त माहितीसह डिक्रिप्ट केलेली स्ट्रिंग कन्सोलवर प्रदर्शित केली गेली. मग आम्ही फाइलमधून पुनर्प्राप्त केलेली वस्तू स्ट्रिंग म्हणून प्रदर्शित केली गेली! म्हणून आम्ही सर्व समस्या यशस्वीरित्या सोडवल्या आहेत :) क्रमवारी आणि डीसीरियलायझेशनचा विषय सोपा वाटतो, परंतु, जसे आपण पाहू शकता, धडे लांब आहेत. आणि आम्ही कव्हर केलेले नाही असे बरेच काही आहे! यापैकी प्रत्येक इंटरफेस वापरताना अजूनही अनेक बारकावे आहेत. परंतु तुमच्या मेंदूला जास्त नवीन माहितीचा स्फोट होऊ नये म्हणून, मी आणखी काही महत्त्वाचे मुद्दे थोडक्यात सूचीबद्ध करेन आणि तुम्हाला अतिरिक्त वाचनासाठी लिंक देईन. तर, आपल्याला आणखी काय माहित असणे आवश्यक आहे? प्रथम , सीरियलायझेशन दरम्यान (तुम्ही वापरत आहात Serializableकिंवा नाही याची पर्वा न करता Externalizable), व्हेरिएबल्सकडे लक्ष द्या static. जेव्हा तुम्ही वापरता Serializable, तेव्हा ही फील्ड अजिबात अनुक्रमित केली जात नाहीत (आणि त्यानुसार, त्यांची मूल्ये बदलत नाहीत, कारण staticफील्ड वर्गाची असतात, ऑब्जेक्टची नाही). पण जेव्हा तुम्ही वापरताExternalizable, तुम्ही प्रक्रिया स्वतः नियंत्रित करता, त्यामुळे तांत्रिकदृष्ट्या तुम्ही त्यांना अनुक्रमित करू शकता. परंतु, आम्ही याची शिफारस करत नाही, कारण असे केल्याने बरेच सूक्ष्म दोष निर्माण होण्याची शक्यता आहे. दुसरे , तुम्ही मॉडिफायरसह व्हेरिएबल्सकडे देखील लक्ष दिले पाहिजे final. जेव्हा तुम्ही वापरता तेव्हा Serializableते नेहमीप्रमाणे अनुक्रमित आणि डीसीरियलाइज केले जातात, परंतु जेव्हा तुम्ही वापरता तेव्हा व्हेरिएबल Externalizableडीसीरियल करणे अशक्य आहेfinal ! कारण सोपे आहे: finalजेव्हा डीफॉल्ट कन्स्ट्रक्टरला कॉल केला जातो तेव्हा सर्व फील्ड सुरू होतात — त्यानंतर, त्यांचे मूल्य बदलले जाऊ शकत नाही. म्हणून, फील्ड असलेल्या ऑब्जेक्ट्सचे क्रमिकरण करण्यासाठी final, द्वारे प्रदान केलेले मानक अनुक्रमिकरण वापरा Serializable. तिसरे , जेव्हा तुम्ही वारसा वापरता तेव्हा सर्व वंशज वर्ग जे काही वारसा घेतातExternalizableक्लासमध्ये डीफॉल्ट कन्स्ट्रक्टर असणे आवश्यक आहे. सीरियलायझेशन मेकॅनिझमबद्दल चांगल्या लेखाची लिंक येथे आहे: पुढच्या वेळे पर्यंत! :)
टिप्पण्या
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION