Serializable và Deserializable trong Java

Chào mừng các bạn đã quay trở lại với thachleblog, bài viết hôm nay mình sẽ trình bày về Serializable và Deserializable trong Java. Mình nghĩ là đa số các bạn mới ra trường sẽ thấy Serializable và Deserializable thật khó hiểu và không biết cách implement (trong đó đã từng có mình, hehe). Hy vọng là sau khi đọc bài viết này, các bạn sẽ thấy Serializable và Deserializable thật đơn giản và có thể áp dụng ngay nếu cần :D.

Định nghĩa

– Serializable là kỹ thuật dùng để convert object thành dạng byte tream (mảng byte) để có thể lưu xuống file hoặc truyền qua mạng.
– Deserilizable sẽ đọc byte stream của object và sau đó convert ngược lại thành object.
Nôm na cho dễ hiểu thì nếu bạn có một cái máy mà khi bạn đưa vào một con bò, nó sẽ cho ra các cây xúc xích, và khi bạn đưa vào cây xúc xích, nó sẽ chuyển đổi các cây xúc xích lại thành lại con bò. Thì con bò chính là object, và Serializable chính là cái máy làm con bò thành xúc xích và Deserializable là cái máy chuyển đổi cây xúc xích thành con bò (đùa chút thôi, mình thích câu truyện cười đó, chứ không có cái máy nào mà đưa vào cây xúc xích mà nó “De” thành con bò đâu, haha).

Tại sao phải Serializable và Deserializable

Đơn giản là để dễ dàng hơn trong việc lưu trữ và xử lý object. Trước kia mình đã từng làm game, khi lưu trữ đối tượng game, mình sẽ lưu từng thuộc tính của nhân vật như máu, đạn… thành từng cột trong file. Khi load game, mình sẽ phải quan tâm đến từng cột data để load cho đúng, trong trường hợp nhân vật của mình có đạn, máu cũng là các object thì sẽ rất rắc rối. Serializable và Deserializable sẽ giúp việc lưu trữ và đọc object trở nên dễ dàng hơn, mình sẽ không cần quan tâm đến các thuộc tính của đối tượng và tổ chức để lưu trữ nữa.

Ngoài ra mình nghĩ việc lưu trữ bằng kỹ thuật Serializable còn có khả năng bảo mật (hồi nhỏ chơi game, mình đã có ý định vào file lưu trữ nhân vật để “hack” mà thất bại vì không đọc được file lưu, rất có thể người ta lưu trữ bằng cơ chế Serializable này, cái này phải hỏi các cao thủ làm game mới biết được, hehe)

serializable va deserializable trong java

Hình minh họa cơ chế Serializable và Deserializable (nguồn internet)

Làm thế nào để implement Serializable?

Để implement Serializable thì object cần implement interface Serializable để “có khả năng” Serializable (xem thêm về interface và abstract class tại đây)
Cơ chế Serializable và Deserializable được thực hiện thông qua:
ObjectOutputStream.writeObject() – serialize object và write
ObjectInputStream.readObject() – deserialize object and read

Ví dụ
Class User: implement interface Serializable

  1. package thach.le;
  2. import java.io.Serializable;
  3. public class User implements Serializable {
  4. private static final long serialVersionUID = 3188831936676695845L;
  5. private String userName;
  6. private String password;
  7. public String getUserName() {
  8. return userName;
  9. }
  10. public void setUserName(String userName) {
  11. this.userName = userName;
  12. }
  13. public String getPassword() {
  14. return password;
  15. }
  16. public void setPassword(String password) {
  17. this.password = password;
  18. }
  19. }

Class SerializationUtil sử dụng ObjectInputStreamObjectOutputStream để Serializable và Deserializable object User

  1. package thach.le;
  2. import java.io.BufferedInputStream;
  3. import java.io.BufferedOutputStream;
  4. import java.io.FileInputStream;
  5. import java.io.FileOutputStream;
  6. import java.io.IOException;
  7. import java.io.ObjectInputStream;
  8. import java.io.ObjectOutputStream;
  9. public class SerializationUtil {
  10. public static Object deserialize(String fileName) throws IOException, ClassNotFoundException {
  11. FileInputStream fis = new FileInputStream(fileName);
  12. Object obj = ois.readObject();
  13. ois.close();
  14. return obj;
  15. }
  16. /**
  17. * serialize the given object and save it to given file
  18. */
  19. public static void serialize(Object obj, String fileName) throws IOException {
  20. FileOutputStream fos = new FileOutputStream(fileName);
  21. oos.writeObject(obj);
  22. oos.close();
  23. }
  24. }

Class SerializableTest: dùng để test 

  1. package thach.le;
  2. import java.io.IOException;
  3. public class SerializableTest {
  4. public static void main(String[] args) {
  5. User user = new User();
  6. user.setUserName("thachlp");
  7. user.setPassword("thachlp");
  8. try {
  9. /**
  10. * Serializing the object
  11. */
  12. SerializationUtil.serialize(user, "serialization.txt");
  13.  
  14. /**
  15. * Deserializing the object
  16. */
  17. User newUser = (User) SerializationUtil.deserialize("serialization.txt");
  18. System.out.println("User name: " + newUser.getUserName());
  19. System.out.println("Password: " + newUser.getPassword());
  20.  
  21. e.printStackTrace();
  22. }
  23. }
  24. }

Kết quả

Sau khi object được serialize và lưu xuống file:

  1. ’ sr
  2. thach.le.User,AÀR % L passwordt Ljava/lang/String;L userNameq ~ xpt thachlpq ~

Sau khi đọc file và deserialize object

  1. User name: thachlp
  2. Password: thachlp

Lưu ý

Trong class User mình có khai báo serialVersionUID bằng final, static, long, vậy:

SerialVersionUID là gì?

– SerialVersionUID là giá trị dùng để định nghĩa thứ tự data của object khi serialize thành byte stream, chúng ta chỉ deserialize object chỉ khi SerialVersionUID của class đúng với SerialVersionUID của instance được lưu trữ.

Không định nghĩa SerialVersionUID thì sao?

  • Cơ chế của Serializable sẽ tự động tạo SerialVersionUID trong quá trình runtime dựa vào các thuộc tính của class, nếu chúng ta không định nghĩa SerialVersionUID và lưu trữ object. Sau đó nếu chúng ta có một vài thay đổi của class và cơ chế của Serializable sẽ tạo ra một SerialVersionUID khác với SerialVersionUID  của instance đang được lưu trữ, chúng ta sẽ gặp lỗi InvalidClassException khi deserialize object (xem thêm về exception tại đây). Do đó phải luôn luôn nhớ định nghĩa SerialVersionUID cho class khi implement Serializable.
  • Cài đặt warning mặc định của eclipse sẽ cảnh báo “The Serializable class User does not declare a static final SerialVersionUID field of type long” khi chúng ta không định nghĩa SerialVersionUID và suggest chúng ta tạo SerialVersionUID.
    Thực chất SerialVersionUID được tạo ra bởi serialver tool nằm trong thư mục bin cài đặt Java (Tham khảo thêm về serialver tool tại đây)

serialversionuid

Hình minh họa tạo SerialVersionUID bằng serialver tool

Từ khóa transent

Từ khóa transent được dùng để định nghĩa thuộc tính khi ta muốn thuộc tính đó không cần được Serializable.

Vừa rồi là phần trình bày của mình về Serializable và Deserializable. Rất mong nhận được ý kiến đóng góp của tất cả các bạn. Hẹn gặp lại các bạn ở các bài viết sau.

Link tải source code: https://github.com/thachlp/SerializableDemo

Tham khảo thêm:
https://www.tutorialspoint.com/java/java_serialization.htm
http://www.codingeek.com/java/io/object-streams-serialization-deserialization-java-example-serializable-interface/
http://javarevisited.blogspot.sg/2014/05/why-use-serialversionuid-inside-serializable-class-in-java.html