CodeGym /Java Blog /अनियमित /जावा में क्रमांकन और अक्रमांकन
John Squirrels
स्तर 41
San Francisco

जावा में क्रमांकन और अक्रमांकन

अनियमित ग्रुप में प्रकाशित
नमस्ते! आज के पाठ में, हम जावा में क्रमांकन और अक्रमांकन के बारे में बात करेंगे। हम एक साधारण उदाहरण के साथ शुरुआत करेंगे। कल्पना कीजिए कि आप एक कंप्यूटर गेम डेवलपर हैं। यदि आप 90 के दशक में पले-बढ़े हैं और उस युग के गेम कंसोल को याद करते हैं, तो आप शायद जानते हैं कि उनमें कुछ कमी थी जिसे हम आज मान लेते हैं - गेम को बचाने और लोड करने की क्षमता :) यदि नहीं, तो कल्पना कीजिए!जावा में क्रमांकन और अक्रमांकन - 1मुझे डर है कि इन क्षमताओं के बिना आज का खेल बर्बाद हो जाएगा! वैसे भी, गेम को 'सेव' और 'लोड' करने का क्या मतलब है? ठीक है, हम रोजमर्रा के अर्थ को समझते हैं: हम खेल को उस जगह से जारी रखना चाहते हैं जहां से हमने छोड़ा था। ऐसा करने के लिए, हम एक निश्चित 'चेक पॉइंट' बनाते हैं जिसका उपयोग हम गेम को लोड करने के लिए बाद में करते हैं। लेकिन एक आकस्मिक गेमर के बजाय एक प्रोग्रामर के लिए इसका क्या मतलब है? उत्तर सरल है: हम अपने कार्यक्रम की स्थिति को सहेजते हैं। मान लीजिए कि आप एक रणनीति खेल में स्पेन खेल रहे हैं। आपके खेल में स्थिति है: सभी के पास कौन से क्षेत्र हैं, सभी के पास कितने संसाधन हैं, कौन से गठबंधन हैं और किसके साथ हैं, कौन युद्ध में है, इत्यादि। यह जानकारी, हमारे कार्यक्रम की स्थिति, डेटा को पुनर्स्थापित करने और खेल को जारी रखने के लिए किसी तरह सहेजी जानी चाहिए। जैसा की होता है, जावा में क्रमांकन बाइट्स के अनुक्रम के रूप में किसी वस्तु की स्थिति को सहेजने की प्रक्रिया है। जावा में Deserialization इन बाइट्स से किसी ऑब्जेक्ट को पुनर्स्थापित करने की प्रक्रिया है। किसी भी जावा ऑब्जेक्ट को बाइट अनुक्रम में परिवर्तित किया जा सकता है। हमें इसकी ज़रूरत क्यों है? हमने बार-बार कहा है कि कार्यक्रम अपने आप में मौजूद नहीं होते हैं। अक्सर, वे एक दूसरे के साथ बातचीत करते हैं, डेटा का आदान-प्रदान करते हैं, आदि। इसके लिए एक बाइट प्रारूप सुविधाजनक और कुशल है। उदाहरण के लिए, हम अपने सेव्डगेम के किसी ऑब्जेक्ट को कन्वर्ट कर सकते हैंक्लास को बाइट्स के अनुक्रम में, इन बाइट्स को नेटवर्क पर दूसरे कंप्यूटर पर स्थानांतरित करें, और फिर दूसरे कंप्यूटर पर इन बाइट्स को वापस जावा ऑब्जेक्ट में परिवर्तित करें! यह मुश्किल लगता है, हुह? ऐसा लगता है कि यह सब करना मुश्किल होगा: / खुशी की बात है कि ऐसा नहीं है! :) जावा में, क्रमांकन प्रक्रिया के लिए Serializable इंटरफ़ेस जिम्मेदार है। यह इंटरफ़ेस अत्यंत सरल है: आपको इसका उपयोग करने के लिए एक ही विधि लागू करने की आवश्यकता नहीं है! खेलों को बचाने के लिए हमारी कक्षा देखें कि यह कितनी सरल है:

import java.io.Serializable;
import java.util.Arrays;

public class SavedGame implements Serializable {

   private static final long serialVersionUID = 1L;

   private String[] territoryInfo;
   private String[] resourceInfo;
   private String[] diplomacyInfo;

   public SavedGame(String[] territoryInfo, String[] resourceInfo, String[] diplomacyInfo){
       this.territoryInfo = territoryInfo;
       this.resourceInfo = resourceInfo;
       this.diplomacyInfo = diplomacyInfo;
   }

   public String[] getTerritoryInfo() {
       return territoryInfo;
   }

   public void setTerritoryInfo(String[] territoryInfo) {
       this.territoryInfo = territoryInfo;
   }

   public String[] getResourceInfo() {
       return resourceInfo;
   }

   public void setResourceInfo(String[] resourceInfo) {
       this.resourceInfo = resourceInfo;
   }

   public String[] getDiplomacyInfo() {
       return diplomacyInfo;
   }

   public void setDiplomacyInfo(String[] diplomacyInfo) {
       this.diplomacyInfo = diplomacyInfo;
   }

   @Override
   public String toString() {
       return "SavedGame{" +
               "territoryInfo=" + Arrays.toString(territoryInfo) +
               ", resourceInfo=" + Arrays.toString(resourceInfo) +
               ", diplomacyInfo=" + Arrays.toString(diplomacyInfo) +
               '}';
   }
}
क्षेत्रों, संसाधनों और कूटनीति के बारे में जानकारी के लिए तीन सरणियाँ जिम्मेदार हैं, और सीरियल करने योग्य इंटरफ़ेस जावा मशीन को बताता है: ' इस वर्ग की वस्तुओं को क्रमबद्ध किया जा सकता है तो सब कुछ ठीक है ।' एक इंटरफ़ेस के बिना एक इंटरफ़ेस अजीब लगता है:/यह आवश्यक क्यों है? उस प्रश्न का उत्तर ऊपर दिया गया है: इसकी आवश्यकता केवल जावा मशीन को आवश्यक जानकारी प्रदान करने के लिए होती है। पिछले पाठ में, हमने संक्षेप में मार्कर इंटरफेस का उल्लेख किया था। ये विशेष सूचनात्मक इंटरफेस हैं जो हमारी कक्षाओं को अतिरिक्त जानकारी के साथ चिह्नित करते हैं जो भविष्य में जावा मशीन के लिए उपयोगी होगी। उनके पास कोई तरीका नहीं है जिसे आपको लागू करना है। यहाँ Serializable है - ऐसा ही एक इंटरफ़ेस। यहाँ एक और महत्वपूर्ण बिंदु है: हमें इसकी आवश्यकता क्यों हैनिजी स्थिर अंतिम लंबा सीरियलवर्जन यूआईडी चर जिसे हमने कक्षा में परिभाषित किया है? इस फ़ील्ड में क्रमबद्ध वर्ग का अद्वितीय संस्करण पहचानकर्ता है। Serializable इंटरफ़ेस को लागू करने वाले प्रत्येक वर्ग में एक संस्करण पहचानकर्ता होता है। यह वर्ग की सामग्री - फ़ील्ड और उनके घोषणा क्रम, और विधियों और उनके घोषणा क्रम के आधार पर निर्धारित किया जाता है। और अगर हम अपनी कक्षा में फ़ील्ड प्रकार और/या फ़ील्ड की संख्या बदलते हैं, तो संस्करण पहचानकर्ता तुरंत बदल जाता है। जब क्लास को सीरियल किया जाता है तो सीरियल वर्जन यूआईडी भी लिखा जाता है। जब हम deserialize करने की कोशिश करते हैं, यानी किसी ऑब्जेक्ट को बाइट अनुक्रम से पुनर्स्थापित करते हैं, तो serialVersionUID के मान की तुलना serialVersionUID के मान से की जाती हैहमारे कार्यक्रम में कक्षा के। यदि मान मेल नहीं खाते हैं, तो java.io.InvalidClassException को फेंक दिया जाएगा। इसका एक उदाहरण हम नीचे देखेंगे। ऐसी स्थितियों से बचने के लिए, हम केवल अपनी कक्षा के लिए संस्करण पहचानकर्ता को मैन्युअल रूप से सेट करते हैं। हमारे मामले में, यह केवल 1 के बराबर होगा (आप अपनी पसंद के किसी अन्य नंबर का उपयोग कर सकते हैं)। खैर, यह हमारे सहेजे गए गेम ऑब्जेक्ट को क्रमबद्ध करने का प्रयास करने का समय है और देखें कि क्या होता है!

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;

public class Main {

   public static void main(String[] args) throws IOException {

       // Create our object
       String[] territoryInfo = {"Spain has 6 provinces", "Russia has 10 provinces", "France has 8 provinces"};
       String[] resourceInfo = {"Spain has 100 gold", "Russia has 80 gold", "France has 90 gold"};
       String[] diplomacyInfo = {"France is at war with Russia, Spain has taken a neutral position"};

       SavedGame savedGame = new SavedGame(territoryInfo, resourceInfo, diplomacyInfo);

       // Create 2 streams to serialize the object and save it to a file
       FileOutputStream outputStream = new FileOutputStream("C:\\Users\\Username\\Desktop\\save.ser");
       ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);

       // Save the game to a file
       objectOutputStream.writeObject(savedGame);

       // Close the stream and release resources
       objectOutputStream.close();
   }
}
जैसा कि आप देख सकते हैं, हमने 2 स्ट्रीम बनाई हैं: FileOutputStream और ObjectOutputStream । पहला जानता है कि फ़ाइल में डेटा कैसे लिखना है, और दूसरा ऑब्जेक्ट को बाइट्स में परिवर्तित करता है। आप पहले से ही इसी तरह के नेस्टेड निर्माणों को देख चुके हैं, उदाहरण के लिए, पिछले पाठों में new BufferedReader(new InputStreamReader(...)) , इसलिए उन्हें आपको डराना नहीं चाहिए :) दो धाराओं की इस श्रृंखला को बनाकर, हम दोनों कार्य करते हैं: हम सहेजे गए गेम ऑब्जेक्ट को बाइट्स के अनुक्रम में परिवर्तित करते हैं और इसे राइटऑब्जेक्ट () विधि का उपयोग करके फ़ाइल में सहेजते हैं। और, वैसे, हमने यह भी नहीं देखा कि हमें क्या मिला! यह फाइल देखने का समय है! *ध्यान दें: फ़ाइल को पहले से बनाना आवश्यक नहीं है। यदि निर्दिष्ट नाम वाली फ़ाइल मौजूद नहीं है, तो यह स्वचालित रूप से बनाई जाएगी* और इसकी सामग्री यहां दी गई है : स्ट्रिंग; РёСЏ заняла позицию нейтралит етаuq ~ t "РЈ Р˜СЃРїР°РЅРёРё 100 золотаt РЈ Р РѕСЃСЃРёРё 80 Р·РѕР» отаt !РЈ Франции 90 Р·РѕР »РѕС‚Р°uq ~ t &РЈ Р˜СЃРїР°РЅРёРё 6 провинцийt %РЈ Р РѕСЃСЃРёР ई 10 ओह, ओह :( ऐसा लगता है कि हमारा कार्यक्रम काम नहीं कर रहा था : ( वास्तव में, यह काम किया। आपको याद है कि हमने फाइल को बाइट्स का एक क्रम भेजा था, और केवल एक वस्तु या पाठ नहीं भेजा था? खैर, यह बाइट अनुक्रम क्या है? ऐसा लगता है :) यह हमारा सहेजा गया खेल है! यदि हम अपनी मूल वस्तु को पुनर्स्थापित करना चाहते हैं, यानी खेल को वहीं से शुरू और जारी रखना चाहते हैं जहां हमने छोड़ा था, तो हमें विपरीत प्रक्रिया की आवश्यकता है: अक्रमांकन। यह हमारे लिए ऐसा दिखता है:

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);

       SavedGame savedGame = (SavedGame) objectInputStream.readObject();

       System.out.println(savedGame);
   }
}
और यहाँ परिणाम है! SavedGame{territoryInfo=[स्पेन के 6 प्रांत हैं, रूस के 10 प्रांत हैं, फ्रांस के 8 प्रांत हैं], ResourceInfo=[स्पेन के पास 100 स्वर्ण हैं, रूस के पास 80 स्वर्ण हैं, फ्रांस के पास 90 स्वर्ण हैं],कूटनीतिInfo=[फ्रांस रूस के साथ युद्ध में है, स्पेन ने तटस्थ स्थिति ली है]} बहुत बढ़िया! हम पहले अपने खेल की स्थिति को फ़ाइल में सहेजने में कामयाब रहे, और फिर इसे फ़ाइल से पुनर्स्थापित करने में कामयाब रहे। अब हम वही काम करने की कोशिश करते हैं, लेकिन हम अपने सेव्डगेम क्लास से वर्जन आइडेंटिफायर को हटा देंगे। हम अपनी दोनों कक्षाओं को दोबारा नहीं लिखेंगे। उनका कोड समान होगा। हम सिर्फ SavedGame क्लास से private static final long serialVersionUID को हटा देंगे। यहाँ क्रमांकन के बाद हमारी वस्तु है: ¬н sr SavedGameі€MіuОm‰ [ डिप्लोमेसीइन्फोट [लजावा/लैंग/स्ट्रिंग;[ रिसोर्सइन्फोक ~ [ टेरिटरीइन्फोक ~ xpur [Ljava.lang.String; С‚ СЃ Россией, Р˜СЃРїР°РЅРёСЏ заняла позицию РЅРµР№С‚СЂР°Р»РёС‚РµС ‚Р°uq ~ t "РЈ Р˜СЃРїР°РЅРёРё 100 золотР°t РЈ Р РѕСЃСЃРёРё 80 золотаt !РЈ Франции 90 золотаuq ~ t &РЈ Р˜СЃРїР°РЅРёРё 6 провинцийt %РЈ 10 अंक ёРЅС†РёР№ लेकिन देखें कि क्या होता है जब हम इसे deserialize करने का प्रयास करते हैं: InvalidClassException: स्थानीय वर्ग असंगत: धारा classdesc serialVersionUID = -196410440475012755, स्थानीय वर्ग serialVersionUID = -6675950253085108747 वैसे, हम कुछ महत्वपूर्ण चूक गए। जाहिर है, तार और आदिम आसानी से क्रमबद्ध होते हैं: जावा में निश्चित रूप से इसके लिए कुछ अंतर्निहित तंत्र हैं। लेकिन क्या होगा अगर हमारे क्रमबद्ध वर्ग में ऐसे क्षेत्र हैं जो आदिम नहीं हैं, बल्कि अन्य वस्तुओं के संदर्भ हैं? उदाहरण के लिए, हमारे सेव्डगेम क्लास के साथ काम करने के लिए अलग-अलग टेरिटरीइन्फो , रिसोर्सइन्फो और डिप्लोमेसीइन्फो क्लास बनाते हैं ।

public class TerritoryInfo {

   private String info;

   public TerritoryInfo(String info) {
       this.info = info;
   }

   public String getInfo() {
       return info;
   }

   public void setInfo(String info) {
       this.info = info;
   }

   @Override
   public String toString() {
       return "TerritoryInfo{" +
               "info='" + info + '\'' +
               '}';
   }
}

public class ResourceInfo {

   private String info;

   public ResourceInfo(String info) {
       this.info = info;
   }

   public String getInfo() {
       return info;
   }

   public void setInfo(String info) {
       this.info = info;
   }

   @Override
   public String toString() {
       return "ResourceInfo{" +
               "info='" + info + '\'' +
               '}';
   }
}

public class DiplomacyInfo {

   private String info;

   public DiplomacyInfo(String info) {
       this.info = info;
   }

   public String getInfo() {
       return info;
   }

   public void setInfo(String info) {
       this.info = info;
   }

   @Override
   public String toString() {
       return "DiplomacyInfo{" +
               "info='" + info + '\'' +
               '}';
   }
}
और अब हमें एक प्रश्न का सामना करना पड़ता है: यदि हम अपने सहेजे गए गेम वर्ग को क्रमबद्ध करना चाहते हैं तो क्या इन सभी वर्गों को क्रमबद्ध होना चाहिए ?

import java.io.Serializable;
import java.util.Arrays;

public class SavedGame implements Serializable {

   private TerritoryInfo territoryInfo;
   private ResourceInfo resourceInfo;
   private DiplomacyInfo diplomacyInfo;

   public SavedGame(TerritoryInfo territoryInfo, ResourceInfo resourceInfo, DiplomacyInfo diplomacyInfo) {
       this.territoryInfo = territoryInfo;
       this.resourceInfo = resourceInfo;
       this.diplomacyInfo = diplomacyInfo;
   }

   public TerritoryInfo getTerritoryInfo() {
       return territoryInfo;
   }

   public void setTerritoryInfo(TerritoryInfo territoryInfo) {
       this.territoryInfo = territoryInfo;
   }

   public ResourceInfo getResourceInfo() {
       return resourceInfo;
   }

   public void setResourceInfo(ResourceInfo resourceInfo) {
       this.resourceInfo = resourceInfo;
   }

   public DiplomacyInfo getDiplomacyInfo() {
       return diplomacyInfo;
   }

   public void setDiplomacyInfo(DiplomacyInfo diplomacyInfo) {
       this.diplomacyInfo = diplomacyInfo;
   }

   @Override
   public String toString() {
       return "SavedGame{" +
               "territoryInfo=" + territoryInfo +
               ", resourceInfo=" + resourceInfo +
               ", diplomacyInfo=" + diplomacyInfo +
               '}';
   }
}
तो ठीक है! आइए इसका परीक्षण करें! अभी के लिए, हम सब कुछ वैसा ही छोड़ देंगे और एक सहेजे गए गेम ऑब्जेक्ट को क्रमबद्ध करने का प्रयास करेंगे:

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;

public class Main {

   public static void main(String[] args) throws IOException {

       // Create our object
       TerritoryInfo territoryInfo = new TerritoryInfo("Spain has 6 provinces, Russia has 10 provinces, France has 8 provinces");
       ResourceInfo resourceInfo = new ResourceInfo("Spain has 100 gold, Russia has 80 gold, France has 90 gold");
       DiplomacyInfo diplomacyInfo =  new DiplomacyInfo("France is at war with Russia, Spain has taken a neutral position");


       SavedGame savedGame = new SavedGame(territoryInfo, resourceInfo, diplomacyInfo);

       FileOutputStream fileOutputStream = new FileOutputStream("C:\\Users\\Username\\Desktop\\save.ser");
       ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);

       objectOutputStream.writeObject(savedGame);

       objectOutputStream.close();
   }
}
परिणाम: थ्रेड में अपवाद "मुख्य" java.io.NotSerializableException: डिप्लोमेसीइन्फो यह काम नहीं किया! तो, यहाँ हमारे प्रश्न का उत्तर है। जब किसी वस्तु को क्रमबद्ध किया जाता है, तो उसके आवृत्ति चर द्वारा संदर्भित सभी वस्तुओं को क्रमबद्ध किया जाता है। और यदि वे वस्तुएँ अन्य वस्तुओं को भी संदर्भित करती हैं, तो वे भी क्रमबद्ध हैं। और हमेशा के लिए। इस श्रंखला की सभी कक्षाएं क्रमबद्ध होनी चाहिए , अन्यथा उन्हें क्रमबद्ध करना असंभव होगा और एक अपवाद फेंक दिया जाएगा। वैसे, यह सड़क के नीचे समस्याएं पैदा कर सकता है। उदाहरण के लिए, यदि हमें क्रमांकन के दौरान किसी वर्ग के भाग की आवश्यकता नहीं है तो हमें क्या करना चाहिए? या क्या होगा अगर हमें लाइब्रेरी के हिस्से के रूप में 'विरासत के माध्यम से' हमारा टेरिटरीइन्फो वर्ग मिला है? और मान लीजिए कि यह 'है'और, तदनुसार, हम इसे बदल नहीं सकते। इसका मतलब यह होगा कि हम अपने सेव्डगेम क्लास में टेरिटरीइन्फो फील्ड नहीं जोड़ सकते हैं , क्योंकि तब पूरी सेव्डगेम क्लास अनसीरियल हो जाएगी! यह एक समस्या है:/ जावा में, इस प्रकार की समस्या क्षणिक कीवर्ड द्वारा हल की जाती है। यदि आप इस खोजशब्द को अपनी कक्षा के किसी क्षेत्र में जोड़ते हैं, तो वह क्षेत्र क्रमबद्ध नहीं होगा। आइए हमारे सहेजे गए गेम क्लास क्षणिक के क्षेत्रों में से एक बनाने का प्रयास करें , और फिर हम एक ऑब्जेक्ट को क्रमबद्ध और पुनर्स्थापित करेंगे। जावा में क्रमांकन और अक्रमांकन - 2

import java.io.Serializable;

public class SavedGame implements Serializable {

   private transient TerritoryInfo territoryInfo;
   private ResourceInfo resourceInfo;
   private DiplomacyInfo diplomacyInfo;

   public SavedGame(TerritoryInfo territoryInfo, ResourceInfo resourceInfo, DiplomacyInfo diplomacyInfo) {
       this.territoryInfo = territoryInfo;
       this.resourceInfo = resourceInfo;
       this.diplomacyInfo = diplomacyInfo;
   }

   // ...getters, setters, toString()...
}



import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;

public class Main {

   public static void main(String[] args) throws IOException {

       // Create our object
       TerritoryInfo territoryInfo = new TerritoryInfo("Spain has 6 provinces, Russia has 10 provinces, France has 8 provinces");
       ResourceInfo resourceInfo = new ResourceInfo("Spain has 100 gold, Russia has 80 gold, France has 90 gold");
       DiplomacyInfo diplomacyInfo =  new DiplomacyInfo("France is at war with Russia, Spain has taken a neutral position");


       SavedGame savedGame = new SavedGame(territoryInfo, resourceInfo, diplomacyInfo);

       FileOutputStream fileOutputStream = new FileOutputStream("C:\\Users\\Username\\Desktop\\save.ser");
       ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);

       objectOutputStream.writeObject(savedGame);

       objectOutputStream.close();
   }
}


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);

       SavedGame savedGame = (SavedGame) objectInputStream.readObject();

       System.out.println(savedGame);

       objectInputStream.close();


   }
}
और परिणाम यह रहा: सेव्डगेम{territoryInfo=null, ResourceInfo=ResourceInfo{info='स्पेन के पास 100 स्वर्ण, रूस के पास 80 स्वर्ण, फ्रांस के पास 90 स्वर्ण'}, diplomacyInfo=DiplomacyInfo{info='फ्रांस रूस, स्पेन के साथ युद्ध में है एक तटस्थ स्थिति ले ली है'}} उस ने कहा, हमें इस सवाल का जवाब मिल गया है कि एक क्षणिक क्षेत्र को क्या मूल्य दिया जाएगा। इसे डिफ़ॉल्ट मान असाइन किया गया है। वस्तुओं के लिए, यह शून्य है । आप इस विषय पर 'हेड-फर्स्ट जावा' पुस्तक में एक उत्कृष्ट अध्याय पढ़ सकते हैं, इस पर ध्यान दें :)
टिप्पणियां
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION