Lớp ObjectOutputStream
(Class ObjectOutputStream)

Lớp ObjectOutputStream kế thừa từ OutputStream và triển khai các giao diện ObjectOutput và ObjectStreamConstants được sử dụng để ghi các kiểu dữ liệu cơ bản và các đối tượng Java vào một OutputStream. Các đối tượng này có thể được đọc (khôi phục) bằng cách sử dụng ObjectInputStream. Nó thực hiện quá trình tuần tự hóa (serialization), biến đổi một đối tượng thành một luồng byte có thể được lưu trữ hoặc truyền đi. Quá trình này cho phép chúng ta lưu trữ trạng thái của một đối tượng vào một file để sử dụng sau này hoặc truyền đối tượng qua mạng.

Một số đặc điểm chính của ObjectOutputStream

↳ Ghi đối tượng: ObjectOutputStream được sử dụng để ghi các đối tượng vào một dòng dữ liệu (stream). Đối tượng được tuần tự hóa (serialized) thành dạng chuỗi byte để có thể lưu trữ hoặc truyền qua mạng. Để ghi một đối tượng, phương thức writeObject() được sử dụng.

↳ Ghi dữ liệu nguyên thủy: Bên cạnh việc ghi các đối tượng, ObjectOutputStream cũng có thể ghi các dữ liệu nguyên thủy như int, char, float, double, v.v., vào dòng dữ liệu. Điều này được thực hiện thông qua các phương thức như writeInt(), writeChar(), v.v.

↳ Chỉ các đối tượng hỗ trợ implements giao diện java.io.Serializable mới có thể được ghi vào luồng dữ liệu.

↳ Bất kỳ đối tượng nào, bao gồm cả chuỗi (Strings) và mảng (arrays), đều được ghi bằng writeObject.

↳ Các tham chiếu đến các đối tượng khác (ngoại trừ trong các trường transient hoặc static) cũng sẽ được ghi.

↳ Các kiểu dữ liệu cơ bản cũng có thể được ghi vào luồng bằng cách sử dụng các phương thức thích hợp từ DataOutput. Các chuỗi có thể được ghi bằng phương thức writeUTF.

Khai báo lớp ObjectOutputStream trong Java

Để sử dụng lớp ObjectOutputStream, bạn cần import gói java.io bạn cần thêm câu lệnh import vào đầu file Java của mình. Gói này cung cấp các lớp và giao diện để thực hiện các hoạt động nhập xuất (I/O) trong Java.

Cú pháp câu lệnh import:

Cú pháp

iimport java.io.ObjectOutputStream;

Cú pháp khai báo lớp ObjectOutputStream:

Cú pháp

public class ObjectOutputStream
extends OutputStream
implements ObjectOutput, ObjectStreamConstants

Dưới đây là giải thích chi tiết về cú pháp khai báo này:

↳ public class ObjectOutputStream: Đây là khai báo một lớp công khai (public) tên là ObjectOutputStream. Lớp này có thể được truy cập từ bất kỳ đâu trong dự án Java, miễn là nó được import hoặc ở cùng gói.

↳ extends OutputStream: Lớp ObjectOutputStream kế thừa từ lớp OutputStream, lớp cơ sở cho các luồng đầu ra byte trong Java. Điều này có nghĩa là ObjectOutputStream có thể ghi dữ liệu xuống một luồng đầu ra, giống như OutputStream.

↳ implements ObjectOutput: Đây là một giao diện (interface) cung cấp các phương thức để ghi các đối tượng vào luồng. ObjectOutputStream triển khai giao diện này để hỗ trợ các phương thức như writeObject(Object obj), writeInt(int v), và writeDouble(double v).

↳ implements ObjectStreamConstants: Đây là một giao diện chứa các hằng số được sử dụng trong tuần tự hóa, chẳng hạn như mã hóa và phiên bản giao thức. ObjectOutputStream triển khai giao diện này để sử dụng các hằng số khi tuần tự hóa các đối tượng.

Lớp lồng nhau bên trong lớp ObjectOutputStream

Lớp ObjectOutputStream có một lớp lồng bên trong duy nhất là:

↳ static class ObjectOutputStream.PutField: Đây là một lớp tĩnh (static class) lồng bên trong lớp ObjectOutputStream. Lớp này cung cấp quyền truy cập chương trình đối với các trường được tuần tự hóa (persistent fields) mà sẽ được ghi vào ObjectOutput

Các Constructor của Lớp ObjectOutputStream

Lớp ObjectOutputStream có hai constructor:

↳ protected ObjectOutputStream(): Là một constructor bảo vệ, được sử dụng nội bộ trong lớp ObjectOutputStream để tạo các lớp con mà không cần phân bổ dữ liệu riêng. Không dùng trực tiếp cho các mục đích thông thường.

↳ ObjectOutputStream(OutputStream out): Tạo một đối tượng ObjectOutputStream để ghi dữ liệu ra luồng đầu ra OutputStream được chỉ định. Đây là constructor chính được sử dụng để tạo đối tượng ObjectOutputStream và bắt đầu ghi dữ liệu ra luồng.

Các phương thức của lớp ObjectOutputStream

Lớp ObjectOutputStream cung cấp các phương thức để ghi dữ liệu ra luồng, bao gồm cả đối tượng, dữ liệu nguyên thủy và thông tin bổ sung. Dưới đây là danh sách tất cả các phương thức của lớp ObjectInputStream trong Java:

↳ void write(byte[] buf): Ghi một mảng byte vào luồng.

↳ void write(byte[] buf, int off, int len): Ghi một phần của mảng byte vào luồng.

↳ void write(int val): Ghi một byte.

↳ void writeBoolean(boolean val): Ghi một giá trị boolean.

↳ void writeByte(int val): Ghi một byte 8 bit.

↳ void writeChar(int val): Ghi một ký tự 16 bit.

↳ void writeDouble(double val): Ghi một số thực 64 bit.

↳ void writeFloat(float val): Ghi một số thực 32 bit.

↳ void writeInt(int val): Ghi một số nguyên 32 bit.

↳ void writeLong(long val): Ghi một số nguyên 64 bit.

↳ void writeShort(int val): Ghi một số nguyên 16 bit.

↳ void writeBytes(String str): Ghi một chuỗi dưới dạng một dãy byte.

↳ void writeChars(String str): Ghi một chuỗi dưới dạng một dãy ký tự.

↳ void writeUTF(String str): Ghi một chuỗi theo định dạng UTF-8.

↳ void writeObject(Object obj): Ghi một đối tượng vào luồng.

↳ protected void writeObjectOverride(Object obj): Phương thức cho phép các lớp con thay thế phương thức ghi đối tượng mặc định.

↳ void writeFields(): Ghi các trường dữ liệu được đệm vào luồng.

↳ protected void writeClassDescriptor(ObjectStreamClass desc): Ghi mô tả lớp vào luồng (chủ yếu dùng cho mục đích nội bộ).

↳ protected void writeStreamHeader(): Phương thức này cho phép các lớp con ghi thêm thông tin vào đầu luồng.

↳ void writeUnshared(Object obj): Ghi một đối tượng "không chia sẻ" vào luồng.

↳ void writeUTF(String str): Ghi một chuỗi theo định dạng UTF-8 vào luồng.

↳ void writeObject(Object obj): Ghi một đối tượng vào luồng.

↳ void defaultWriteObject(): Ghi các trường không tĩnh và không transient của lớp hiện tại vào luồng.

↳ ObjectOutputStream.PutField putFields(): Trả về một đối tượng để lưu trữ các trường dữ liệu liên quan đến đối tượng trước khi ghi vào luồng.

↳ void close(): Đóng luồng đầu ra.

↳ void flush(): Xả dữ liệu đệm ra luồng.

↳ protected void drain(): Xả dữ liệu đệm nội bộ của ObjectOutputStream.

↳ protected void annotateClass(Class<?> cl): Cho phép các lớp con lưu trữ dữ liệu bổ sung về lớp vào luồng (chủ yếu dùng cho mục đích nội bộ).

↳ protected void annotateProxyClass(Class<?> cl): Cho phép các lớp con lưu trữ dữ liệu tùy chỉnh trong luồng cùng với mô tả cho các lớp proxy động (chủ yếu dùng cho mục đích nội bộ).

↳ protected boolean enableReplaceObject(boolean enable): Cho phép thay thế đối tượng trong quá trình tuần tự hóa (chủ yếu dùng cho mục đích nội bộ).

↳ protected Object replaceObject(Object obj): Phương thức cho phép các lớp con thay thế đối tượng trong quá trình tuần tự hóa (chủ yếu dùng cho mục đích nội bộ).

↳ void useProtocolVersion(int version): Chỉ định phiên bản giao thức luồng khi ghi dữ liệu.

↳ protected void readStreamHeader(): Đọc tiêu đề của luồng (chủ yếu dùng cho mục đích nội bộ).

Ví dụ:

Dưới đây là một vài ví dụ về cách sử dụng ObjectOutputStream trong Java để tuần tự hóa đối tượng (serialize) và ghi chúng vào tệp tin:

Ví dụ 1: Tuần tự hóa đối tượng đơn giản

Trong ví dụ này, chúng ta sẽ tuần tự hóa một đối tượng đơn giản của lớp MyClass và ghi nó vào một tệp tin.

Ví dụ: Example.java

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;

class MyClass implements java.io.Serializable {
    private String message;
    private int number;

    public MyClass(String message, int number) {
        this.message = message;
        this.number = number;
    }

    @Override
    public String toString() {
        return "MyClass{" +
                "message='" + message + '\'' +
                ", number=" + number +
                '}';
    }
}

public class Example {
    public static void main(String[] args) {
        MyClass obj = new MyClass("Hello, World!", 123);
        
        try (FileOutputStream fileOut = new FileOutputStream("objectdata.ser");
             ObjectOutputStream out = new ObjectOutputStream(fileOut)) {
            
            out.writeObject(obj);
            System.out.println("Đối tượng đã được tuần tự hóa và ghi vào file objectdata.ser");

        } catch (IOException i) {
            i.printStackTrace();
        }
    }
}

Khi chương trình chạy thành công, tệp objectdata.ser sẽ chứa nội dung như sau:

���sr�MyClass���7�����I�numberL�messaget�Ljava/lang/String;xp���{t�
Hello, World!

Ví dụ 2: Tuần tự hóa một danh sách các đối tượng

Ví dụ này sẽ tuần tự hóa một danh sách các đối tượng MyClass và ghi chúng vào một tệp tin.

Ví dụ: Example.java

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.List;

class MyClass implements java.io.Serializable {
    private String message;
    private int number;

    public MyClass(String message, int number) {
        this.message = message;
        this.number = number;
    }

    @Override
    public String toString() {
        return "MyClass{" +
                "message='" + message + '\'' +
                ", number=" + number +
                '}';
    }
}

public class Example {
    public static void main(String[] args) {
        List<MyClass> myList = new ArrayList<>();
        myList.add(new MyClass("Message 1", 101));
        myList.add(new MyClass("Message 2", 202));
        myList.add(new MyClass("Message 3", 303));
        
        try (FileOutputStream fileOut = new FileOutputStream("objectlist.ser");
             ObjectOutputStream out = new ObjectOutputStream(fileOut)) {
            
            out.writeObject(myList);
            System.out.println("Danh sách đối tượng đã được tuần tự hóa và ghi vào file objectlist.ser");

        } catch (IOException i) {
            i.printStackTrace();
        }
    }
}

Khi chương trình chạy thành công, tệp objectdata.ser sẽ chứa nội dung như sau:

���sr�java.util.ArrayListx����a� �I�
sizexp��� w
��� sr�MyClass���7�����I�numberL�messaget�L
java/lang/String;xp���et� Message 1sq�~�����t� Message
2sq�~���/t� Message 3x

Các ví dụ trên cho thấy cách sử dụng ObjectOutputStream để tuần tự hóa các đối tượng đơn lẻ, danh sách đối tượng, và cả đối tượng có các thuộc tính tạm thời. ObjectOutputStream là một công cụ mạnh mẽ trong Java để làm việc với tuần tự hóa đối tượng, giúp lưu trữ trạng thái của đối tượng vào file để có thể tái sử dụng sau này.

Câu Nói Truyền Cảm Hứng

“Bắt đầu ở đâu không quan trọng, quan trọng là bạn sẵn sàng bắt đầu.” – W. Clement Stone

Không Gian Tích Cực

“Chúc bạn luôn giữ vững niềm tin và sức mạnh để vượt qua mọi thử thách trong cuộc sống.”