شنبه ۲۹ دي ۱۴۰۳
Tut24 آموزش برنامه نویسی و مجله تخصصی فناوری ورود/عضویت

آموزش جاوا - سریال سازی

جاوا یک مکانیزم فراهم می‌کند که به آن سریالی‌سازی شیء می‌گویند، که در آن یک شیء می‌تواند به عنوان یک توالی از بایت‌ها نمایش داده شود که شامل داده‌های شیء، اطلاعاتی درباره نوع شیء و نوع داده‌های ذخیره شده در شیء است.

پس از اینکه یک شیء سریالی‌سازی شده به یک فایل نوشته شده باشد، می‌توان آن را از فایل خواند و سریالی‌سازی را بازیابی کرد، به این معنی که اطلاعات نوع و بایت‌هایی که شیء و داده‌های آن را نمایش می‌دهند، مورد استفاده قرار می‌گیرند تا شیء را در حافظه بازسازی کنند.

جالب‌ترین موضوع این است که کل فرآیند مستقل از محیط اجرای JVM است، به این معنی که یک شیء می‌تواند در یک پلتفرم سریالی‌سازی شود و در یک پلتفرم کاملاً متفاوت بازسازی شود.

کلاس‌های ObjectInputStream و ObjectOutputStream جریان‌های سطح بالا هستند که حاوی متدهای سریالی‌سازی و بازسازی یک شیء هستند.

کلاس ObjectOutputStream شامل بسیاری از متدهای نوشتن برای نوشتن انواع مختلف داده است، اما یک متد به طور ویژه برجسته است −


public final void writeObject(Object x) throws IOException

متد فوق یک شیء را سریالی‌سازی می‌کند و آن را به جریان خروجی ارسال می‌کند. به طریق مشابه، کلاس ObjectInputStream شامل متد زیر برای بازسازی یک شیء است −


public final Object readObject() throws IOException, ClassNotFoundException

این متد شیء بعدی را از جریان بازیابی کرده و بازسازی می‌کند. مقدار بازگشتی Object است، بنابراین شما باید آن را به نوع داده‌ای مناسب تبدیل کنید.

برای نشان دادن نحوه کار سریالی‌سازی در جاوا، قصد دارم از کلاس Employee استفاده کنم که در ابتدای کتاب درباره آن صحبت کرده‌ایم. فرض کنید که کلاس Employee زیر را داریم که رابط Serializable را پیاده‌سازی می‌کند −

مثال


public class Employee implements java.io.Serializable {
   public String name;
   public String address;
   public transient int SSN;
   public int number;
   
   public void mailCheck() {
      System.out.println("Mailing a check to " + name + " " + address);
   }
}

توجه کنید که برای سریالی‌سازی موفق یک کلاس، دو شرط باید برآورده شود −

  • کلاس باید رابط java.io.Serializable را پیاده‌سازی کند.

  • تمامی فیلدهای کلاس باید قابل سریالی‌سازی باشند. اگر یک فیلد قابل سریالی‌سازی نباشد، باید با transient علامت گذاری شود.

اگر دوست دارید بدانید که یک کلاس استاندارد جاوا قابل سریالی‌سازی است یا خیر، به مستندات کلاس مراجعه کنید. آزمون ساده است: اگر کلاس رابط java.io.Serializable را پیاده‌سازی کند، آنگاه قابل سریالی‌سازی است؛ در غیر اینصورت، قابل سریالی‌سازی نیست.

سریالی‌سازی یک شیء

کلاس ObjectOutputStream برای سریالی‌سازی یک شیء استفاده می‌شود. برنامه SerializeDemo زیر یک شیء Employee را نمونه‌سازی کرده و آن را سریالی‌سازی می‌کند.

هنگام اجرای برنامه، یک فایل به نام employee.ser ایجاد می‌شود. برنامه هیچ خروجی‌ای تولید نمی‌کند، اما کد را مطالعه کنید و سعی کنید بفهمید برنامه چه کاری انجام می‌دهد.

توجه − هنگام سریالی‌سازی یک شیء به یک فایل، عادت معمول در جاوا این است که فایل را با پسوند .ser نامگذاری کنید.

مثال


import java.io.*;
public class SerializeDemo {

   public static void main(String [] args) {
      Employee e = new Employee();
      e.name = "Reyan Ali";
      e.address = "Phokka Kuan, Ambehta Peer";
      e.SSN = 11122333;
      e.number = 101;
      
      try {
         FileOutputStream fileOut =
         new FileOutputStream("/tmp/employee.ser");
         ObjectOutputStream out = new ObjectOutputStream(fileOut);
         out.writeObject(e);
         out.close();
         fileOut.close();
         System.out.printf("Serialized data is saved in /tmp/employee.ser");
      } catch (IOException i) {
         i.printStackTrace();
      }
   }
}

بازیابی (Deserializing) یک شیء

برنامه DeserializeDemo زیر شیء Employee را که در برنامه SerializeDemo سریالی‌سازی شده است، بازیابی می‌کند. کد را مطالعه کنید و سعی کنید خروجی آن را تشخیص دهید −

مثال


import java.io.*;
public class DeserializeDemo {

   public static void main(String [] args) {
      Employee e = null;
      try {
         FileInputStream fileIn = new FileInputStream("/tmp/employee.ser");
         ObjectInputStream in = new ObjectInputStream(fileIn);
         e = (Employee) in.readObject();
         in.close();
         fileIn.close();
      } catch (IOException i) {
         i.printStackTrace();
         return;
      } catch (ClassNotFoundException c) {
         System.out.println("Employee class not found");
         c.printStackTrace();
         return;
      }
      
      System.out.println("Deserialized Employee...");
      System.out.println("Name: " + e.name);
      System.out.println("Address: " + e.address);
      System.out.println("SSN: " + e.SSN);
      System.out.println("Number: " + e.number);
   }
}

این به نتیجه زیر منجر می‌شود −

خروجی


Deserialized Employee...
Name: Reyan Ali
Address:Phokka Kuan, Ambehta Peer
SSN: 0
Number:101

در ادامه نکات مهم زیر باید مورد توجه قرار گیرد −

  • بلوک try/catch سعی می‌کند یک ClassNotFoundException را که توسط متد readObject() اعلام شده است، بگیرد. برای JVM قابلیت بازسازی (Deserialization) یک شیء، باید قادر به پیدا کردن بایت‌کد (bytecode) کلاس باشد. اگر JVM نتواند در هنگام بازسازی یک شیء، یک کلاس را پیدا کند، یک ClassNotFoundException پرتاب می‌کند.

  • توجه کنید که مقدار بازگشتی readObject() به یک ارجاع Employee تبدیل شده است.

  • مقدار فیلد SSN هنگام سریال‌سازی شیء 11122333 بوده است، اما به دلیل transient بودن فیلد، این مقدار به جریان خروجی ارسال نشده است. مقدار فیلد SSN در شیء بازسازی شده Employee برابر با 0 است.