JavaRush /בלוג Java /Random-HE /איך עובדת סריאליזציה ב-Java
ramhead
רָמָה

איך עובדת סריאליזציה ב-Java

פורסם בקבוצה
במאמר זה נסביר מהי סדרה וכיצד היא פועלת ב-Java. איך עובדת סריאליזציה ב-Java - 1

מבוא

סריאליזציה של אובייקט היא היכולת של אובייקט לאחסן עותק שלם של עצמו ושל כל אובייקט אחר שהוא מפנה באמצעות זרם פלט (לדוגמה, לקובץ חיצוני). בדרך זו, ניתן ליצור מחדש את האובייקט מהעותק המוסדר (שמר) מעט מאוחר יותר בעת הצורך. הסדרת אובייקטים, תכונה חדשה שהוצגה ב-JDK 1.1, מספקת פונקציה להמרת קבוצות או אובייקטים בודדים, לזרם סיביות או מערך בתים, לאחסון או שידור ברשת. וכאמור, זרם סיביות נתון או מערך בתים ניתן להמיר בחזרה לאובייקטי Java. זה קורה בעיקר אוטומטית הודות לשיעורים ObjectInputStreamו ObjectOutputStream. המתכנת עשוי להחליט ליישם פונקציונליות זו על ידי הטמעת הממשק Serializableבעת יצירת המחלקה. תהליך ההמשכה מכונה גם ארגון אובייקטים , ואילו דה-סריאליזציה ידועה כ- Unmarshaling . סריאליזציה היא מנגנון המאפשר לאובייקט לשמור עותק של עצמו ושל כל שאר האובייקטים שהאובייקט הזה מפנה אליו לקובץ חיצוני באמצעות ה- ObjectOutputStream. האובייקטים השמורים יכולים להיות מבני נתונים, דיאגרמות, אובייקטי מחלקה JFrameאו כל אובייקט אחר, ללא קשר לסוגם. במקביל, הסידרה מאחסנת מידע על סוג האובייקט, כך שבהמשך, כאשר הוא דה-סיריאליז, המידע הזה משמש לשחזור הסוג המדויק של האובייקט שהיה. אז, סדרה מספקת את היכולות הבאות:
  • מערכת לאחסון אובייקטים, כלומר: שמירת מאפיינים בקובץ חיצוני, בדיסק או במסד נתונים.
  • מערכת קריאת נוהל מרחוק.
  • מערכת הפצת אובייקטים, למשל, ברכיבי תוכנה כמו COM, COBRA.
  • מערכת לזיהוי שינויים בנתונים משתנים לאורך זמן.
כדי להבין במלואו את המושג של סריאליזציה, אתה צריך להיות בעל הבנה ברורה של שני המושגים האחרים - התמדה של אובייקט והתמדה של חוט. כאן נדבר מעט על כל אחד מהם על מנת לזכור. הסבר מלא שלהם ידרוש פרק נפרד לכל אחד מהמושגים הללו.

זרמים:

כל תוכנית חייבת לכתוב את הנתונים שלה למקום אחסון או לצינור, וכל תוכנית חייבת לקרוא נתונים מצינור או מיקום אחסון. ב-Java, ערוצים אלה שבהם תוכניות כותבות וממנו תוכניות קוראים נתונים נקראים Streams ( Stream) . איך עובדת סריאליזציה ב-Java - 2
איור 1. ייצוג גרפי של חוטים
הזרמים מתחלקים בעיקר לשני סוגים:
  • מחלקות זרם בתים הנקראות *זרמים
  • כיתות זרם תווים בשם *Reader ו-*Writer
כל זרם כתיבת נתונים מכיל קבוצה של שיטות כתיבה. ולכל שרשור קריאת נתונים, בהתאם, יש קבוצה דומה של שיטות קריאה. לאחר יצירת השרשור, יש לקרוא לכל השיטות הללו.

הַתמָדָה

התמדה באובייקט היא היכולת של אובייקט לחיות או, במילים אחרות, "לשרוד" את ביצועה של תוכנית. משמעות הדבר היא שכל אובייקט שנוצר בזמן ריצה מושמד על ידי השואב JVM בכל פעם שאובייקט זה אינו בשימוש עוד. אבל אם ה-API של persistence מיושם, האובייקטים הללו לא יושמדו על ידי השואב JVM, במקום זאת הם יורשו "לחיות", מה שמאפשר גם לגשת אליהם בפעם הבאה שהאפליקציה תופעל. במילים אחרות, התמדה פירושה שיש חיים שלמים לאובייקט, ללא תלות באורך החיים של האפליקציה שפועלת. אחת הדרכים ליישם התמדה היא לאחסן אובייקטים במקום כלשהו בקובץ חיצוני או במסד נתונים, ולאחר מכן לשחזר אותם במועד מאוחר יותר באמצעות קבצים אלה או מסד הנתונים כמקורות. כאן נכנסת לתמונה ההסדרה. כל אובייקט לא מתמשך קיים כל עוד ה-JVM פועל. אובייקטים מסודרים הם פשוט אובייקטים המומרים לזרמים, שנשמרים לאחר מכן בקובץ חיצוני או מועברים דרך רשת לאחסון ושחזור.

הטמעת ממשק Serializable

כל מחלקה חייבת ליישם ממשק java.io.Serializableכדי להרכיב אובייקטים של אותה מחלקה. לממשק Serializableאין שיטות והוא מסמן רק את המחלקה כך שניתן לזהות אותה כניתנת לסידרה. ניתן לשמור רק את השדות של אובייקט מחלקה מסודר. שיטות או בנאים אינם מאוחסנים כחלק מהזרם המסודר. אם אובייקט כלשהו פועל כהתייחסות לאובייקט אחר, השדות של האובייקט הזה גם מסודרים אם המחלקה של האובייקט מיישמת את הממשק Serializable. במילים אחרות, הגרף של אובייקט זה שהתקבל כך ניתן לסידרה לחלוטין. גרף אובייקטים כולל עץ או מבנה של שדות של אובייקט ואובייקטי המשנה שלו. שתי מחלקות עיקריות המסייעות ביישום הממשק Seriliazable:
  • ObjectInputStream
  • ObjectOutputStream
רשימה 1. דוגמה למחלקה פשוטה להצגת סדרה
import java.io.*;
public class RandomClass implements Serializable {
 // Генерация рандомного значения
 private static int r() {
        return (int)(Math.random() * 10);
 }
    private int data[];
    // Конструктор
public RandomClass() {
        datafile = new int[r()];
        for (int i=0; i<datafile.length; i++)
        datafile[i]=r();
 }
    public void printout() {
 System.out.println("This RandomClass has "+datafile.length+" random integers");
 for (int i=0; i<datafile.length; i++) {
        System.out.print(datafile[i]+":");
        System.out.println();
    }
}
בקוד לעיל, נוצרת מחלקה הניתנת לסידרה בגלל "מסומן" על ידי ממשק הסידרה. המחלקה יוצרת מערך של מספרים שלמים אקראיים כאשר נוצר מופע שלו. הקוד שלהלן מציג את היכולת לכתוב אובייקטים לזרם באמצעות ה- ObjectOutputStream. לתוכנית יש מערך של מספרים שלמים, אבל בשביל הסדרה אנחנו לא צריכים לחזור על האובייקטים הפנימיים שלה. הממשק Seriliazableמטפל בזה באופן אוטומטי. רישום 2. דוגמה פשוטה להסדרת אובייקטים לפלט לקובץ
import java.io.*;
import java.util.*;
public class OutSerialize {
    public static void main (String args[]) throws IOException {
        RandomClass rc1 = new RandomClass();
        RandomClass rc2 = new RandomClass();
//создание цепи потоков с потоком вывода an object в конце
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("objects.dat"));
        Date now = new Date(System.currentTimeMillis());
//java.util.* был импортирован для использования класса Date
        out.writeObject(now);
        out.writeObject(rc1);
        out.writeObject(rc2);
out.close();
        System.out.println("I have written:");
System.out.println("A Date object: "+now);
        System.out.println("Two Group of randoms");
rc1.printout();
rc2.printout();
 }
}
הקוד שלהלן מדגים את היכולות של המחלקה ObjectInputStream, שקוראת נתונים מסודרים מקובץ חיצוני לתוך תוכנית. שימו לב שהאובייקטים נקראים באותו סדר שבו נכתבו לקובץ. רישום 3. קריאת אובייקטים מסודרים או דה-סריאליזציה
import java.io.*;
import java.util.*;
public class InSerialize {
 public static void main (String args[]) throws  IOException, ClassNotFoundException {
    ObjectInputStream in =  new ObjectInputStream (new FileInputStream("objects.dat"));
 Date d1 = (Date)in.readObject();
 RandomClass rc1 = (RandomClass)in.readObject();
    RandomClass rc2 = (RandomClass)in.readObject();
    System.out.println("I have read:");
    System.out.println("A Date object: "+d1);
    System.out.println("Two Group of randoms");
    rc1.printout();
rc2.printout();
 }
}
כמעט כל מחלקות Java ניתנות לסידרה, כולל מחלקות AWT. מסגרת, שהיא חלון, מכילה קבוצה של רכיבים גרפיים. אם המסגרת מסודרת, מנוע הסדרת דואג לכך ומעביר את כל הרכיבים והנתונים שלו (מיקום, תוכן וכו'). חלק מאובייקטי מחלקת Java לא ניתנים לסידרה מכיוון שהם מכילים נתונים המפנים למשאבי מערכת הפעלה ארעיים. למשל שיעורים java.io.FileInputStreamו java.lang.Thread. אם אובייקט מכיל הפניות לרכיבים שאינם ניתנים להמשכה, פעולת ההמשכה כולה תיכשל ויוצא חריג NotSerializableException. אם אובייקט כלשהו מתייחס להפניה של אובייקט לא מסודר, ניתן לבצע אותו בסידרה באמצעות מילת המפתח החולפת . רישום 4. יצירת אובייקטים הניתנים לסידרה באמצעות מילת המפתח החולפת
public class Sclass implements Serializable{
public transient Thread newThread;
//помните, что поток(поток параллельного исполнения) по умолчанию не сериализуемый класс
    private String studentID;
    private int sum;
}

אבטחה בסידרה

הסדרת מחלקה ב-Java כרוכה בהעברת כל הנתונים שלה לקובץ או מסד נתונים חיצוניים באמצעות זרם. אנו יכולים להגביל את הנתונים שיוסדרו בכל עת שנרצה. ישנן שתי דרכים לעשות זאת:
  • כל פרמטר מחלקה שהוכרז כחולף אינו מסודר (כברירת מחדל, כל פרמטרי המחלקה מסודרים)
  • לחלופין, כל פרמטר של המחלקה שברצוננו לעשות בסידרה מסומן בתג Externalizable(כברירת מחדל, אין פרמטרים מסודרים).
שדה נתונים לא יופיע בסידרה עם ObjectOutputStream, כאשר נקרא על אובייקט, אם שדה הנתונים של האובייקט מסומן כחולף . לדוגמה: private transient String password. מצד שני, כדי להכריז במפורש על נתוני אובייקט כניתנים לסידרה, עלינו לסמן את המחלקה ככותבת ExternalizablewriteExternalוקוראת במפורש readExteranlאת הנתונים של אותו אובייקט.

סיכום

התכונה של סדרת אובייקטים משמשת במערכות מבוזרות רבות כדרך להעברת נתונים. אבל הסידרה חושפת פרטים נסתרים, ובכך הורסת את האותנטיות של סוגי נתונים מופשטים, שבתורה הורסת אנקפסולציה. יחד עם זאת, נחמד לדעת שהנתונים של האובייקט המסודר הם אותם נתונים שהיו באובייקט המקורי, המקורי. זו גם הזדמנות מצוינת ליישם ממשק ObjectInputValidationולעקוף שיטה validateObject(), גם אם נעשה שימוש במספר שורות קוד. אם האובייקט לא נמצא, נוכל לזרוק חריג כראוי InvalidObjectException. מאמר מקורי: איך עובדת סדרה ב-Java
הערות
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION