Chuyển Đổi Object Với Serialization Trong Java
Khi lập trình với Java chắc hẳn bạn đã bắt gặp từ khóa Serializable trong các thao tác đọc ghi file hay mapping với cơ sở dữ liệu. Trong các thao tác trao đổi dữ liệu trên thì dữ liệu cần được thể hiện dưới dạng byte chứ không phải dạng object được khai báo lúc đầu, do đó java đã giới thiệu khái niệm Serialization để hỗ trợ cho việc trao đổi dữ liệu giữa các thành phần với nhau.
1. Serialization là gì?
Như đã nói ở trên java cung cấp cho chúng ta công cụ Serialization để giúp chuyển đổi các object (đối tượng) thành các dòng bytes, ở đó lưu trữ tất cả các dữ liệu của object như kiểu dữ liệu, giá trị các biến hay các methods.
Thông thường Serialization gồm 2 qua trình là Serializing và Deserializing, trong khi serializing giúp chuyển đổi object thành các dòng bytes thì ngược lại deserializing chuyển các dòng bytes đã được serializing thành objects với các dữ liệu được giữ nguyên.
Công việc trên được thực hiện độc lập bởi JVM, điều đó có nghĩa rằng một object được serializing ở nền tảng này mà vẫn có thể được deserializing ở nền tảng khác. Đặc điểm này cũng đã chứng minh slogan “Write once, Run anywhere” gắn liền với Java từ trước đến nay.
Chú ý: để serializing thành công thì class của object cần thực thi (implements) Serializable Interface của java (java.io.Serializable).
Hai quá trình này sẽ được mình trình bày dưới đây thông qua thao tác ghi file gắn với quá trình serializing và đọc file gắn với deserializing.
Trước tiên chúng ta cần tạo một class Employees và hàm main như sau:
class Employees implements Serializable {
public String id;
public transient String password;
//biến khai bao với transient sẽ không được serialize
public String name;
public int age;
//Constructor
public Employees() {
}
//In thông tin
public void showInfor(){
System.out.println("ID: "+ this.id);
System.out.println("Password: "+this.password);
System.out.println("Name: "+this.name);
System.out.println("Age: "+this.age);
}
}
Hàm main:
public static void main(String[] args) {
//Tạo 1 đối tượng và khai báo dữ liệu
Employees employee = new Employees();
employee.id = "123456";
employee.password = "88888888";
employee.name = "user1";
employee.age = 21;
//Serialize bằng hàm serialize() với tham số truyền vào là employee
serialize(employee);
//Deserialize bàng hàm Deserialize()
deserialize();
}
2. Serializing
Chúng ta sẽ sử dụng lớp ObjectOutputStream
, là một Stream cấp cao để serializing một object. Lớp ObjectOutputStream
bao gồm nhiều phương thức write để ghi các kiểu dữ liệu khác nhau nhưng ở đây chúng ta sẽ sử dụng phương thức writeObject()
.
Phương thức writeObject
nhận tham số đầu vào là một object sau đó sẽ thực hiện serializing và gửi kết quả vào stream. Ngoài ra, phương thức này throw/throws một Input/Output Exception nên cần được bao bởi try-catch.
Sau đây là khai triển của phương thức serialize()
thuộc hàm main bên trên:
public static void serialize(Employees employee){
try {
FileOutputStream fileOut = new FileOutputStream("./src/employees.ser");
ObjectOutputStream out = new ObjectOutputStream(fileOut);
out.writeObject(employee);
out.close();
fileOut.close();
System.out.println("Save object successfully!");
} catch (IOException e) {
e.printStackTrace();
}
}
Chú ý:
- Các thuộc tính không cần serializing sẽ được khai báo với từ khoá
transient
. - Quy ước khi serializing thành một file ta cần khai báo tên file với đuôi .ser.
Sau khi chạy thành công, chương trình trả về kế quả “Save object successfully” và một file employees.ser sẽ xuất hiện, còn không sẽ trả về lỗi IOExcception.
3. Deserializing
Tương tự với serializing, java cung cấp lớp ObjectInputStream
dùng cho việc deserializing thông qua phương thức readObject()
.
Phương thức readObject lần lượt truy xuất các objects đã được serializing trong stream sau đó deserializing chúng và trả về các objects. Giống với writeObject thì readObject cũng cần được bao trong khối try-catch.
Sau đây là khai triển của phương thức deserialize()
thuộc hàm main bên trên:
private static void deserialize() {
try{
FileInputStream fileInput = new FileInputStream("./src/employees.ser");
ObjectInputStream input = new ObjectInputStream(fileInput);
//readObject trả về một Object nên cần ép về kiểu Employees
Employees employee = (Employees) input.readObject();
System.out.println("Read object from File:");
//Hiện thông tin
employee.showInfor();
}catch(IOException e){
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
Khối try-catch này sẽ bắt lỗi IOException
trong trường hợp không tìm thấy file, và lỗi ClassNotFoundException
trong trường hợp không tìm thấy khai báo đối tượng employee.
Kết quả sau khi chạy thành công sẽ in các thuộc tính của đối tượng employee mà ta đã khai báo ở hàm main:
Save object successfully!
Read object from File:
ID: 123456
Password: null
Name: user1
Age: 21
Như các bạn có thể thấy thuộc tính password không có dữ liệu do nó được khai báo với từ khóa transient
.
Kết
Nếu bài viết có ý nghĩa, bạn hãy để lại đánh giá cũng như comment bên dưới giúp phát triển bài viết tốt hơn. Cảm ơn các bạn đã đọc!