Προγραμματισμός

Αποκαλύφθηκε ο αλγόριθμος σειριοποίησης Java

Σειριοποίηση είναι η διαδικασία αποθήκευσης της κατάστασης ενός αντικειμένου σε μια ακολουθία byte. αποεστεροποίηση είναι η διαδικασία ανακατασκευής αυτών των byte σε ζωντανό αντικείμενο. Το Java Serialization API παρέχει έναν τυπικό μηχανισμό για τους προγραμματιστές να χειρίζονται την σειριοποίηση αντικειμένων. Σε αυτήν την συμβουλή, θα δείτε πώς να κάνετε σειριοποίηση ενός αντικειμένου και γιατί η σειριοποίηση είναι μερικές φορές απαραίτητη. Θα μάθετε για τον αλγόριθμο σειριοποίησης που χρησιμοποιείται στην Java και θα δείτε ένα παράδειγμα που απεικονίζει τη σειριακή μορφή ενός αντικειμένου. Μέχρι να τελειώσετε, θα πρέπει να έχετε μια καλή γνώση για το πώς λειτουργεί ο αλγόριθμος σειριοποίησης και ποιες οντότητες σειριοποιούνται ως μέρος του αντικειμένου σε χαμηλό επίπεδο.

Γιατί απαιτείται σειριοποίηση;

Στον σημερινό κόσμο, μια τυπική εταιρική εφαρμογή θα έχει πολλά στοιχεία και θα διανεμηθεί σε διάφορα συστήματα και δίκτυα. Στην Java, όλα αντιπροσωπεύονται ως αντικείμενα. Εάν δύο στοιχεία Java θέλουν να επικοινωνούν μεταξύ τους, πρέπει να υπάρχει ένας μηχανισμός ανταλλαγής δεδομένων. Ένας τρόπος για να το επιτύχετε αυτό είναι να ορίσετε το δικό σας πρωτόκολλο και να μεταφέρετε ένα αντικείμενο. Αυτό σημαίνει ότι το τέλος λήψης πρέπει να γνωρίζει το πρωτόκολλο που χρησιμοποιεί ο αποστολέας για την εκ νέου δημιουργία του αντικειμένου, κάτι που θα καθιστούσε πολύ δύσκολη την επικοινωνία με στοιχεία τρίτων. Ως εκ τούτου, πρέπει να υπάρχει ένα γενικό και αποτελεσματικό πρωτόκολλο για τη μεταφορά του αντικειμένου μεταξύ των στοιχείων. Η σειριοποίηση ορίζεται για αυτό το σκοπό και τα στοιχεία Java χρησιμοποιούν αυτό το πρωτόκολλο για τη μεταφορά αντικειμένων.

Το σχήμα 1 δείχνει μια προβολή υψηλού επιπέδου επικοινωνίας πελάτη / διακομιστή, όπου ένα αντικείμενο μεταφέρεται από τον πελάτη στον διακομιστή μέσω σειριοποίησης.

Σχήμα 1. Μια προβολή υψηλού επιπέδου της σειριοποίησης σε δράση (κάντε κλικ για μεγέθυνση)

Πώς να κάνετε σειριοποίηση ενός αντικειμένου

Για να σειριοποιήσετε ένα αντικείμενο, πρέπει να βεβαιωθείτε ότι η κλάση του αντικειμένου εφαρμόζει το java.io.Serializable διεπαφή, όπως φαίνεται στην καταχώριση 1.

Λίστα 1. Υλοποίηση με δυνατότητα σειριοποίησης

 εισαγωγή java.io.Serializable; class TestSerial εργαλεία Serializable {public byte version = 100; αριθμός δημόσιων byte = 0; } 

Στην Λίστα 1, το μόνο πράγμα που έπρεπε να κάνετε διαφορετικά από τη δημιουργία μιας κανονικής τάξης είναι να εφαρμόσετε το java.io.Serializable διεπαφή. ο Σειριοποιήσιμο διεπαφή είναι μια διεπαφή δείκτη? δεν δηλώνει καθόλου μεθόδους. Λέει στον μηχανισμό σειριοποίησης ότι η τάξη μπορεί να σειριοποιηθεί.

Τώρα που έχετε κάνει την τάξη επιλέξιμη για σειριοποίηση, το επόμενο βήμα είναι να κάνετε σειριοποίηση του αντικειμένου. Αυτό γίνεται καλώντας το writeObject () μέθοδος του java.io.ObjectOutputStream τάξη, όπως φαίνεται στην καταχώριση 2.

Λίστα 2. Κλήση writeObject ()

 public static void main (String args []) ρίχνει το IOException {FileOutputStream fos = new FileOutputStream ("temp.out"); ObjectOutputStream oos = νέο ObjectOutputStream (fos); TestSerial ts = νέο TestSerial (); oos.writeObject (ts); oos.flush (); oos.close (); } 

Η λίστα 2 αποθηκεύει την κατάσταση του TestSerial αντικείμενο σε ένα αρχείο που ονομάζεται temp.out. oos.writeObject (ts); στην πραγματικότητα ξεκινά τον αλγόριθμο σειριοποίησης, με τον οποίο γράφει το αντικείμενο temp.out.

Για να δημιουργήσετε ξανά το αντικείμενο από το μόνιμο αρχείο, θα χρησιμοποιήσετε τον κώδικα στην Λίστα 3.

Λίστα 3. Αναδημιουργία σειριακού αντικειμένου

 public static void main (String args []) ρίχνει το IOException {FileInputStream fis = new FileInputStream ("temp.out"); ObjectInputStream oin = νέο ObjectInputStream (fis); TestSerial ts = (TestSerial) oin.readObject (); System.out.println ("version =" + ts.version); } 

Στην λίστα 3, η αποκατάσταση του αντικειμένου γίνεται με το oin.readObject () μέθοδος κλήσης. Αυτή η κλήση μεθόδου διαβάζει στα ακατέργαστα byte που προηγουμένως επιμείναμε και δημιουργεί ένα ζωντανό αντικείμενο που είναι ένα ακριβές αντίγραφο του αρχικού γραφήματος αντικειμένου. Επειδή readObject () μπορεί να διαβάσει οποιοδήποτε σειριοποιήσιμο αντικείμενο, απαιτείται ένα cast στον σωστό τύπο.

Εκτελώντας αυτόν τον κωδικό θα εκτυπωθεί έκδοση = 100 στην τυπική έξοδο.

Η σειριακή μορφή ενός αντικειμένου

Πώς μοιάζει η σειριακή έκδοση του αντικειμένου; Θυμηθείτε, το δείγμα κώδικα στην προηγούμενη ενότητα έσωσε τη σειριακή έκδοση του TestSerial αντικείμενο στο αρχείο temp.out. Η λίστα 4 δείχνει το περιεχόμενο του temp.out, εμφανίζεται σε δεκαεξαδικό. (Χρειάζεστε έναν δεκαεξαδικό επεξεργαστή για να δείτε την έξοδο σε δεκαεξαδική μορφή.)

Λίστα 4. Δεκαεξαδική μορφή TestSerial

 AC ED 00 05 73 72 00 0A 53 65 72 69 61 6C 54 65 73 74 A0 0C 34 00 FE B1 DD F9 02 00 02 42 00 05 63 6F 75 6E 74 42 00 07 76 65 72 73 69 6F 6E 78 70 00 64 

Αν κοιτάξετε ξανά το πραγματικό TestSerial αντικείμενο, θα δείτε ότι έχει μόνο δύο μέλη byte, όπως φαίνεται στην καταχώριση 5.

Λίστα 5. Μέλη byte του TestSerial

 δημόσια έκδοση byte = 100; αριθμός δημόσιων byte = 0; 

Το μέγεθος μιας μεταβλητής byte είναι ένα byte, και ως εκ τούτου το συνολικό μέγεθος του αντικειμένου (χωρίς την κεφαλίδα) είναι δύο byte. Αλλά αν κοιτάξετε το μέγεθος του σειριακού αντικειμένου στην Λίστα 4, θα δείτε 51 byte. Εκπληξη! Από πού προέρχονται τα επιπλέον byte και ποια είναι η σημασία τους; Εισάγονται από τον αλγόριθμο σειριοποίησης και απαιτούνται για την αναδημιουργία του αντικειμένου. Στην επόμενη ενότητα, θα εξερευνήσετε λεπτομερώς αυτόν τον αλγόριθμο.

Αλγόριθμος σειριοποίησης Java

Μέχρι τώρα, θα πρέπει να έχετε μια πολύ καλή γνώση του πώς να κάνετε σειριοποίηση ενός αντικειμένου. Αλλά πώς λειτουργεί η διαδικασία κάτω από την κουκούλα; Σε γενικές γραμμές ο αλγόριθμος σειριοποίησης κάνει τα εξής:

  • Καταγράφει τα μεταδεδομένα της κλάσης που σχετίζεται με μια παρουσία.
  • Γράφει αναδρομικά την περιγραφή του superclass μέχρι να το βρει java.lang.object.
  • Μόλις ολοκληρώσει τη σύνταξη των πληροφοριών μεταδεδομένων, ξεκινά με τα πραγματικά δεδομένα που σχετίζονται με την παρουσία. Αλλά αυτή τη φορά, ξεκινά από το κορυφαίο superclass.
  • Γράφει αναδρομικά τα δεδομένα που σχετίζονται με την παρουσία, ξεκινώντας από το λιγότερο superclass μέχρι την πιο παράγωγη κλάση.

Έχω γράψει ένα διαφορετικό παράδειγμα αντικειμένου για αυτήν την ενότητα που θα καλύπτει όλες τις πιθανές περιπτώσεις. Το νέο αντικείμενο δείγματος που πρόκειται να σειριοποιηθεί εμφανίζεται στη λίστα 6.

Λίστα 6. Δείγμα σειριακού αντικειμένου

 το class parent υλοποιεί το Serializable {int parentVersion = 10; } κλάση περιέχει εργαλεία Serializable {int containVersion = 11; } Η δημόσια τάξη SerialTest επεκτείνει τα μητρικά εργαλεία Serializable {int version = 66; περιέχει con = νέο περιέχει (); public int getVersion () {έκδοση επιστροφής; } public static void main (String args []) ρίχνει το IOException {FileOutputStream fos = new FileOutputStream ("temp.out"); ObjectOutputStream oos = νέο ObjectOutputStream (fos); SerialTest st = νέο SerialTest (); oos.writeObject (st); oos.flush (); oos.close (); }} 

Αυτό το παράδειγμα είναι απλό. Σειριοποιεί ένα αντικείμενο τύπου Σειριακό τεστ, το οποίο προέρχεται από μητρική εταιρεία και έχει αντικείμενο κοντέινερ, περιέχω. Η σειριακή μορφή αυτού του αντικειμένου εμφανίζεται στη λίστα 7.

Λίστα 7. Σειριακή μορφή δείγματος αντικειμένου

 AC ED 00 05 73 72 00 0A 53 65 72 69 61 6C 54 65 73 74 05 52 81 5A AC 66 02 F6 02 00 02 49 00 07 76 65 72 73 69 6F 6E 4C 00 03 63 6F 6E 74 00 09 4C 63 6F 6E 74 61 69 6E 3B 78 72 00 06 70 61 72 65 6E 74 0E DB D2 BD 85 EE 63 7A 02 00 01 49 00 0D 70 61 72 65 6E 74 56 65 72 73 69 6F 6E 78 70 00 00 00 0A 00 00 00 42 73 72 00 07 63 6F 6E 74 61 69 6E FC BB E6 0E FB CB 60 C7 02 00 01 49 00 0E 63 6F 6E 74 61 69 6E 56 65 72 73 69 6F 6E 78 70 00 00 00 0B 

Το Σχήμα 2 προσφέρει μια ματιά υψηλού επιπέδου στον αλγόριθμο σειριοποίησης για αυτό το σενάριο.

Σχήμα 2. Ένα περίγραμμα του αλγορίθμου σειριοποίησης

Ας δούμε λεπτομερώς τη σειριακή μορφή του αντικειμένου και να δούμε τι αντιπροσωπεύει κάθε byte. Ξεκινήστε με τις πληροφορίες πρωτοκόλλου σειριοποίησης:

  • AC ΕΔ: STREAM_MAGIC. Καθορίζει ότι αυτό είναι ένα πρωτόκολλο σειριοποίησης.
  • 00 05: STREAM_VERSION. Η έκδοση σειριοποίησης.
  • 0x73: TC_OBJECT. Καθορίζει ότι πρόκειται για νέο Αντικείμενο.

Το πρώτο βήμα του αλγορίθμου σειριοποίησης είναι να γράψετε την περιγραφή της κλάσης που σχετίζεται με μια παρουσία. Το παράδειγμα σειριοποιεί ένα αντικείμενο τύπου Σειριακό τεστ, έτσι ο αλγόριθμος ξεκινά γράφοντας την περιγραφή του Σειριακό τεστ τάξη.

  • 0x72: TC_CLASSDESC. Καθορίζει ότι πρόκειται για μια νέα τάξη.
  • 00 0Α: Μήκος του ονόματος τάξης.
  • 53 65 72 69 61 6γ 54 65 73 74: Σειριακό τεστ, το όνομα της τάξης.
  • 05 52 81 5A AC 66 02 F6: SerialVersionUID, το αναγνωριστικό σειριακής έκδοσης αυτής της κλάσης.
  • 0x02: Διάφορες σημαίες. Αυτή η συγκεκριμένη σημαία λέει ότι το αντικείμενο υποστηρίζει σειριοποίηση.
  • 00 02: Αριθμός πεδίων σε αυτήν την τάξη.

Στη συνέχεια, ο αλγόριθμος γράφει το πεδίο int έκδοση = 66;.

  • 0x49: Κωδικός τύπου πεδίου. Το 49 αντιπροσωπεύει το "I", που σημαίνει Εντ.
  • 00 07: Μήκος του ονόματος πεδίου.
  • 76 65 72 73 69 6F 6Ε: εκδοχή, το όνομα του πεδίου.

Και μετά ο αλγόριθμος γράφει το επόμενο πεδίο, περιέχει con = νέο περιέχει ();. Αυτό είναι ένα αντικείμενο, οπότε θα γράψει την κανονική υπογραφή JVM αυτού του πεδίου.

  • 0x74: TC_STRING. Αντιπροσωπεύει μια νέα συμβολοσειρά.
  • 00 09: Μήκος της συμβολοσειράς.
  • 4C 63 6F 6E 74 61 69 6E 3Β: Lcontain;, η κανονική υπογραφή JVM.
  • 0x78: TC_ENDBLOCKDATA, το τέλος των προαιρετικών δεδομένων μπλοκ για ένα αντικείμενο.

Το επόμενο βήμα του αλγορίθμου είναι να γράψετε την περιγραφή του μητρική εταιρεία τάξη, η οποία είναι η άμεση superclass της Σειριακό τεστ.

  • 0x72: TC_CLASSDESC. Καθορίζει ότι πρόκειται για μια νέα τάξη.
  • 00 06: Μήκος του ονόματος τάξης.
  • 70 61 72 65 6Ε 74: Σειριακό τεστ, το όνομα της τάξης
  • 0E DB D2 BD 85 EE 63 7A: SerialVersionUID, το αναγνωριστικό σειριακής έκδοσης αυτής της κλάσης.
  • 0x02: Διάφορες σημαίες. Αυτή η σημαία σημειώνει ότι το αντικείμενο υποστηρίζει σειριοποίηση.
  • 00 01: Αριθμός πεδίων σε αυτήν την τάξη.

Τώρα ο αλγόριθμος θα γράψει την περιγραφή πεδίου για το μητρική εταιρεία τάξη. μητρική εταιρεία έχει ένα πεδίο, int parentVersion = 100;.

  • 0x49: Κωδικός τύπου πεδίου. Το 49 αντιπροσωπεύει το "I", που σημαίνει Εντ.
  • 00 0D: Μήκος του ονόματος πεδίου.
  • 70 61 72 65 6E 74 56 65 72 73 69 6F 6Ε: γονική έκδοση, το όνομα του πεδίου.
  • 0x78: TC_ENDBLOCKDATA, το τέλος των δεδομένων μπλοκ για αυτό το αντικείμενο.
  • 0x70: TC_NULL, το οποίο αντιπροσωπεύει το γεγονός ότι δεν υπάρχουν πλέον σούπερ γυαλιά, επειδή έχουμε φτάσει στην κορυφή της ιεραρχίας της τάξης.

Μέχρι στιγμής, ο αλγόριθμος σειριοποίησης έχει γράψει την περιγραφή της κλάσης που σχετίζεται με την παρουσία και όλα τα superclasses της. Στη συνέχεια, θα γράψει τα πραγματικά δεδομένα που σχετίζονται με την παρουσία. Γράφει πρώτα τα γονικά μέλη της τάξης:

  • 00 00 00 0Α: 10, η τιμή του γονική έκδοση.

Στη συνέχεια προχωράει προς Σειριακό τεστ.

  • 00 00 00 42: 66, η τιμή του εκδοχή.

Τα επόμενα λίγα byte είναι ενδιαφέροντα. Ο αλγόριθμος πρέπει να γράψει τις πληροφορίες για το περιέχω αντικείμενο, που εμφανίζεται στην καταχώριση 8.

Λίστα 8. Το αντικείμενο περιέχει

 περιέχει con = νέο περιέχει (); 

Θυμηθείτε, ο αλγόριθμος σειριοποίησης δεν έχει γράψει την περιγραφή τάξης για το περιέχω τάξη ακόμα. Αυτή είναι η ευκαιρία να γράψετε αυτήν την περιγραφή.

  • 0x73: TC_OBJECT, ορίζοντας ένα νέο αντικείμενο.
  • 0x72: TC_CLASSDESC.
  • 00 07: Μήκος του ονόματος τάξης.
  • 63 6F 6E 74 61 69 6Ε: περιέχω, το όνομα της τάξης.
  • FC BB E6 0E FB CB 60 C7: SerialVersionUID, το αναγνωριστικό σειριακής έκδοσης αυτής της κλάσης.
  • 0x02: Διάφορες σημαίες. Αυτή η σημαία υποδεικνύει ότι αυτή η τάξη υποστηρίζει σειριοποίηση.
  • 00 01: Αριθμός πεδίων σε αυτήν την τάξη.

Στη συνέχεια, ο αλγόριθμος πρέπει να γράψει την περιγραφή για περιέχωτο μοναδικό πεδίο, int containVersion = 11;.

  • 0x49: Κωδικός τύπου πεδίου. Το 49 αντιπροσωπεύει το "I", που σημαίνει Εντ.
  • 00 0Ε: Μήκος του ονόματος πεδίου.
  • 63 6F 6E 74 61 69 6E 56 65 72 73 69 6F 6Ε: containVersion, το όνομα του πεδίου.
  • 0x78: TC_ENDBLOCKDATA.

Στη συνέχεια, ο αλγόριθμος σειριοποίησης ελέγχει για να δει εάν περιέχω έχει οποιεσδήποτε τάξεις γονέων. Αν το έκανε, ο αλγόριθμος θα άρχιζε να γράφει αυτήν την τάξη. αλλά σε αυτήν την περίπτωση δεν υπάρχει superclass για περιέχωγράφει ο αλγόριθμος TC_NULL.

  • 0x70: TC_NULL.

Τέλος, ο αλγόριθμος γράφει τα πραγματικά δεδομένα που σχετίζονται με περιέχω.

  • 00 00 00 0Β: 11, η τιμή του containVersion.

συμπέρασμα

Σε αυτήν την συμβουλή, έχετε δει πώς να σειριοποιήσετε ένα αντικείμενο και μάθατε πώς λειτουργεί ο αλγόριθμος σειριοποίησης. Ελπίζω αυτό το άρθρο να σας δώσει περισσότερες λεπτομέρειες σχετικά με το τι συμβαίνει όταν πραγματικά κάνετε σειριοποίηση ενός αντικειμένου.

Σχετικά με τον Συγγραφέα

Η Sathiskumar Palaniappan έχει περισσότερα από τέσσερα χρόνια εμπειρίας στη βιομηχανία πληροφορικής και συνεργάζεται με τεχνολογίες που σχετίζονται με την Java για περισσότερα από τρία χρόνια. Επί του παρόντος, εργάζεται ως μηχανικός λογισμικού συστήματος στο Java Technology Center, IBM Labs. Έχει επίσης εμπειρία στον κλάδο των τηλεπικοινωνιών.

Πόροι

  • Διαβάστε την προδιαγραφή σειριοποίησης αντικειμένου Java. (Η προδιαγραφή είναι PDF.)
  • "Ισιώστε τα αντικείμενά σας: Ανακαλύψτε τα μυστικά του Java Serialization API" (Todd M. Greanier, JavaWorld, Ιούλιος 2000) προσφέρει μια ματιά στα παξιμάδια της διαδικασίας σειριοποίησης.
  • Κεφάλαιο 10 του Java RMI (William Grosso, O'Reilly, Οκτώβριος 2001) είναι επίσης μια χρήσιμη αναφορά.

Αυτή η ιστορία, "Ο αλγόριθμος σειριοποίησης Java αποκαλύφθηκε" δημοσιεύθηκε αρχικά από το JavaWorld.