Tuần tự hóa đối tượng là gì?


384

"Tuần tự hóa đối tượng" có nghĩa là gì? Bạn có thể vui lòng giải thích nó với một số ví dụ?


2
Trong trường hợp bạn quan tâm đến một kịch bản Java EE trong thế giới thực có liên quan đến tuần tự hóa, hãy truy cập vào đây: stackoverflow.com/q/2294551
BalusC

Câu trả lời:


400

Tuần tự hóa là việc chuyển đổi một đối tượng thành một chuỗi byte, để đối tượng có thể dễ dàng lưu vào bộ lưu trữ liên tục hoặc truyền qua một liên kết truyền thông. Luồng byte sau đó có thể được giải tuần tự hóa - được chuyển đổi thành một bản sao của đối tượng ban đầu.


16
điều này có bắt buộc không? Tôi có phải tuần tự hóa dữ liệu trước khi gửi không? nó được chuyển đổi sang định dạng nào?
Francisco Corrales Morales

15
@FranciscoCorralesMorales - Đằng sau hậu trường, tất cả dữ liệu sẽ được tuần tự hóa trước khi nó được gửi qua một luồng. Bạn cần phải làm bao nhiêu và định dạng của nó là gì, đều phụ thuộc vào nền tảng và thư viện bạn đang sử dụng.
TarkaDaal

3
@FranciscoCorralesMorales Bạn nói thế nào? ý tôi là bạn đang nói định dạng phụ thuộc vào nền tảng và thư viện. Tôi thực sự muốn biết định dạng.
JAVA

1
Có áp dụng cho chỉ các đối tượng? Chúng ta có thể tuần tự hóa các biến (khai báo mà không sử dụng các đối tượng) không?
Rumado

Chỉ đối tượng @Rumado
anKotliner

395

Bạn có thể nghĩ về tuần tự hóa như là quá trình chuyển đổi một thể hiện đối tượng thành một chuỗi byte (có thể là nhị phân hoặc không phụ thuộc vào việc thực hiện).

Nó rất hữu ích khi bạn muốn truyền một dữ liệu đối tượng qua mạng, ví dụ từ JVM này sang JVM khác.

Trong Java, cơ chế tuần tự hóa được tích hợp vào nền tảng, nhưng bạn cần triển khai giao diện Nối tiếp để tạo một đối tượng tuần tự hóa.

Bạn cũng có thể ngăn một số dữ liệu trong đối tượng của mình khỏi bị xê-ri hóa bằng cách đánh dấu thuộc tính là nhất thời .

Cuối cùng, bạn có thể ghi đè cơ chế mặc định và cung cấp cơ chế của riêng bạn; điều này có thể phù hợp trong một số trường hợp đặc biệt Để làm điều này, bạn sử dụng một trong những tính năng ẩn trong java .

Điều quan trọng cần lưu ý là những gì được tuần tự hóa là "giá trị" của đối tượng, hoặc nội dung, chứ không phải định nghĩa lớp. Do đó phương pháp không được tuần tự hóa.

Đây là một mẫu rất cơ bản với các bình luận để tạo điều kiện cho việc đọc của nó:

import java.io.*;
import java.util.*;

// This class implements "Serializable" to let the system know
// it's ok to do it. You as programmer are aware of that.
public class SerializationSample implements Serializable {

    // These attributes conform the "value" of the object.

    // These two will be serialized;
    private String aString = "The value of that string";
    private int    someInteger = 0;

    // But this won't since it is marked as transient.
    private transient List<File> unInterestingLongLongList;

    // Main method to test.
    public static void main( String [] args ) throws IOException  { 

        // Create a sample object, that contains the default values.
        SerializationSample instance = new SerializationSample();

        // The "ObjectOutputStream" class has the default 
        // definition to serialize an object.
        ObjectOutputStream oos = new ObjectOutputStream( 
                               // By using "FileOutputStream" we will 
                               // Write it to a File in the file system
                               // It could have been a Socket to another 
                               // machine, a database, an in memory array, etc.
                               new FileOutputStream(new File("o.ser")));

        // do the magic  
        oos.writeObject( instance );
        // close the writing.
        oos.close();
    }
}

Khi chúng tôi chạy chương trình này, tệp "o.ser" được tạo và chúng tôi có thể thấy những gì đã xảy ra đằng sau.

Nếu chúng ta thay đổi giá trị của: someInteger thành, ví dụ Integer.MAX_VALUE , chúng ta có thể so sánh đầu ra để xem sự khác biệt là gì.

Đây là một ảnh chụp màn hình cho thấy chính xác sự khác biệt đó:

văn bản thay thế

Bạn có thể nhận ra sự khác biệt? ;)

Có một trường liên quan bổ sung trong tuần tự hóa Java: serialversionUID nhưng tôi đoán điều này đã quá dài để bao quát nó.


1
@ raam86 dụ là đối tượng được tuần tự hóa. Bạn có thể nghĩ trong phương thức chính là một chương trình riêng biệt tạo ra một đối tượng thuộc loạiSerializationSample
OscarRyz

2
@ raam86 là câu lệnh đầu tiên trong phương thức chính: SerializationSample instance = new SerializationSample();sau đó đầu ra được tạo và đối tượng được ghi vào đầu ra đó.
OscarRyz

1
Oh. Không folow đủ gần. Tuyệt quá!!
raam86

1
@jacktrades Tại sao bạn không thử. Chỉ cần sao chép / dán ví dụ và thấy "NotSerializableException" bị ném :)
OscarRyz

1
@jacktrades vì ​​máy tính chưa được thông báo rằng đối tượng được phép nối tiếp :) oos có nghĩa là gì?
Chris Bennett

101

Sẵn sàng trả lời câu hỏi 6 năm tuổi, chỉ thêm một sự hiểu biết rất cao cho những người mới biết về Java

Tuần tự hóa là gì?

Chuyển đổi một đối tượng thành byte

Deserialization là gì?

Chuyển đổi byte trở lại một đối tượng (Deserialization).

Khi nào được xê-ri hóa được sử dụng?

Khi chúng ta muốn kiên trì đối tượng. Khi chúng ta muốn đối tượng tồn tại ngoài vòng đời của JVM.

Ví dụ thế giới thực:

ATM: Khi chủ tài khoản cố gắng rút tiền từ máy chủ thông qua ATM, thông tin chủ tài khoản như chi tiết rút tiền sẽ được tuần tự hóa và gửi đến máy chủ nơi các chi tiết được giải tuần tự hóa và được sử dụng để thực hiện các hoạt động.

Làm thế nào serialization được thực hiện trong java.

  1. java.io.SerializableGiao diện triển khai (giao diện đánh dấu để không có phương pháp để thực hiện).

  2. Kiên trì đối tượng: Sử dụng java.io.ObjectOutputStreamlớp, luồng bộ lọc là trình bao bọc xung quanh luồng byte cấp thấp hơn (để ghi Đối tượng vào hệ thống tệp hoặc chuyển đối tượng được làm phẳng qua dây mạng và được xây dựng lại ở phía bên kia).

    • writeObject(<<instance>>) - để viết một đối tượng
    • readObject() - để đọc một đối tượng được tuần tự hóa

Nhớ lại:

Khi bạn tuần tự hóa một đối tượng, chỉ trạng thái của đối tượng sẽ được lưu, không phải tệp hoặc phương thức lớp của đối tượng.

Khi bạn tuần tự hóa một đối tượng 2 byte, bạn sẽ thấy tệp tuần tự 51 byte.

Các bước làm thế nào đối tượng được tuần tự hóa và khử nối tiếp.

Trả lời cho: Làm thế nào mà nó chuyển đổi thành tập tin 51 byte?

  • Đầu tiên ghi dữ liệu ma thuật dòng tuần tự hóa (STREAM_MAGIC = "AC ED" và STREAM_VERSION = phiên bản của JVM).
  • Sau đó, nó viết ra siêu dữ liệu của lớp được liên kết với một thể hiện (độ dài của lớp, tên của lớp, serialVersionUID).
  • Sau đó, nó đệ quy viết ra siêu dữ liệu của siêu lớp cho đến khi tìm thấy java.lang.Object.
  • Sau đó bắt đầu với dữ liệu thực tế liên quan đến thể hiện.
  • Cuối cùng ghi dữ liệu của các đối tượng được liên kết với thể hiện bắt đầu từ siêu dữ liệu đến nội dung thực tế.

Nếu bạn quan tâm đến thông tin sâu hơn về Tuần tự hóa Java, vui lòng kiểm tra liên kết này .

Chỉnh sửa : Thêm một liên kết tốt để đọc.

Điều này sẽ trả lời một vài câu hỏi thường gặp:

  1. Làm thế nào để không tuần tự hóa bất kỳ lĩnh vực trong lớp.
    Trả lời: sử dụng từ khóa thoáng qua

  2. Khi lớp con được tuần tự hóa, lớp cha có được tuần tự hóa không?
    Trả lời: Không, Nếu cha mẹ không mở rộng trường cha mẹ giao diện Nối tiếp thì không được nối tiếp.

  3. Khi cha mẹ được tuần tự hóa, lớp con có được tuần tự hóa không?
    Trả lời: Có, theo mặc định, lớp con cũng được tuần tự hóa.

  4. Làm thế nào để tránh lớp con khỏi bị nối tiếp?
    Trả lời: a. Ghi đè phương thức writeObject và readObject và ném NotSerializableException.

    b. bạn cũng có thể đánh dấu tất cả các trường thoáng qua trong lớp con.

  5. Một số lớp cấp hệ thống như Thread, OutputStream và các lớp con của nó và Socket không được tuần tự hóa.

3
cảm ơn bạn rất nhiều vì câu trả lời ngắn gọn này, nó rất hữu ích!
Nobi

21

Tuần tự hóa đang lấy một đối tượng "sống" trong bộ nhớ và chuyển đổi nó thành định dạng có thể được lưu trữ ở đâu đó (ví dụ: trong bộ nhớ, trên đĩa) và sau đó "giải trừ" trở lại thành một đối tượng sống.


14

Tôi thích cách trình bày @OscarRyz. Mặc dù ở đây tôi đang tiếp tục câu chuyện nối tiếp được viết bởi @amitgupta.

Mặc dù biết về cấu trúc lớp robot và có dữ liệu tuần tự, nhà khoa học của Trái đất không thể giải tuần tự hóa dữ liệu có thể khiến robot hoạt động.

Exception in thread "main" java.io.InvalidClassException:
SerializeMe; local class incompatible: stream classdesc
:

Các nhà khoa học của sao Hỏa đang chờ đợi thanh toán đầy đủ. Sau khi thanh toán xong, các nhà khoa học của Mars đã chia sẻ serialversionUID với các nhà khoa học của Trái đất. Nhà khoa học của Trái đất đặt nó vào lớp robot và mọi thứ trở nên tốt đẹp.


9

Tuần tự hóa có nghĩa là các đối tượng bền bỉ trong java. Nếu bạn muốn lưu trạng thái của đối tượng và muốn xây dựng lại trạng thái sau (có thể trong một JVM khác) có thể sử dụng tuần tự hóa.

Lưu ý rằng các thuộc tính của một đối tượng sẽ chỉ được lưu. Nếu bạn muốn phục hồi lại đối tượng, bạn nên có tệp lớp, bởi vì các biến thành viên sẽ chỉ được lưu trữ chứ không phải các hàm thành viên.

ví dụ:

ObjectInputStream oos = new ObjectInputStream(                                 
                                 new FileInputStream(  new File("o.ser")) ) ;
SerializationSample SS = (SearializationSample) oos.readObject();

Searializable là một giao diện đánh dấu đánh dấu rằng lớp của bạn được tuần tự hóa. Giao diện đánh dấu có nghĩa là nó chỉ là một giao diện trống và sử dụng giao diện đó sẽ thông báo cho JVM rằng lớp này có thể được tạo thành tuần tự hóa.


9

Hai xu của tôi từ blog của riêng tôi:

Dưới đây là một lời giải thích chi tiết về Tuần tự hóa : (blog của riêng tôi)

Tuần tự hóa:

Tuần tự hóa là quá trình duy trì trạng thái của một đối tượng. Nó được biểu diễn và lưu trữ dưới dạng một chuỗi các byte. Điều này có thể được lưu trữ trong một tập tin. Quá trình đọc trạng thái của đối tượng từ tệp và khôi phục nó được gọi là khử lưu huỳnh.

Sự cần thiết của serialization là gì?

Trong kiến ​​trúc hiện đại, luôn có nhu cầu lưu trữ trạng thái đối tượng và sau đó lấy nó. Ví dụ, trong Hibernate, để lưu trữ một đối tượng, chúng ta nên tạo lớp Nối tiếp. Những gì nó làm, là một khi trạng thái đối tượng được lưu dưới dạng byte, nó có thể được chuyển sang một hệ thống khác mà sau đó có thể đọc từ trạng thái và truy xuất lớp. Trạng thái đối tượng có thể đến từ cơ sở dữ liệu hoặc jvm khác hoặc từ một thành phần riêng biệt. Với sự trợ giúp của Tuần tự hóa, chúng ta có thể truy xuất trạng thái Đối tượng.

Mã ví dụ và giải thích:

Trước tiên, hãy xem Class Item:

public class Item implements Serializable{

    /**
    *  This is the Serializable class
    */
    private static final long serialVersionUID = 475918891428093041L;
    private Long itemId;
    private String itemName;
    private transient Double itemCostPrice;
    public Item(Long itemId, String itemName, Double itemCostPrice) {
        super();
        this.itemId = itemId;
        this.itemName = itemName;
        this.itemCostPrice = itemCostPrice;
      }

      public Long getItemId() {
          return itemId;
      }

     @Override
      public String toString() {
          return "Item [itemId=" + itemId + ", itemName=" + itemName + ", itemCostPrice=" + itemCostPrice + "]";
       }


       public void setItemId(Long itemId) {
           this.itemId = itemId;
       }

       public String getItemName() {
           return itemName;
       }
       public void setItemName(String itemName) {
            this.itemName = itemName;
        }

       public Double getItemCostPrice() {
            return itemCostPrice;
        }

        public void setItemCostPrice(Double itemCostPrice) {
             this.itemCostPrice = itemCostPrice;
        }
}

Trong đoạn mã trên có thể thấy rằng lớp Item thực hiện Nối tiếp .

Đây là giao diện cho phép một lớp được tuần tự hóa.

Bây giờ chúng ta có thể thấy một biến được gọi là serialVersionUID được khởi tạo thành biến Long. Số này được tính toán bởi trình biên dịch dựa trên trạng thái của lớp và các thuộc tính của lớp. Đây là con số sẽ giúp jvm xác định trạng thái của một đối tượng khi nó đọc trạng thái của đối tượng từ tệp.

Về điều đó, chúng ta có thể xem Tài liệu chính thức của Oracle:

Thời gian chạy tuần tự hóa liên kết với mỗi lớp tuần tự hóa một số phiên bản, được gọi là serialVersionUID, được sử dụng trong quá trình giải tuần tự hóa để xác minh rằng người gửi và người nhận của một đối tượng được tuần tự hóa đã tải các lớp cho đối tượng đó tương thích với tuần tự hóa. Nếu người nhận đã tải một lớp cho đối tượng có serialVersionUID khác với lớp của người gửi tương ứng, thì quá trình khử lưu huỳnh sẽ dẫn đến một UnlimitedClassException. Một lớp tuần tự hóa có thể khai báo serialVersionUID của riêng mình một cách rõ ràng bằng cách khai báo một trường có tên "serialVersionUID" phải là tĩnh, cuối cùng và có kiểu dài: ANY-ACCESS-MODifyER nối tiếp tĩnh dài serialVersionUID = 42L; Nếu một lớp tuần tự hóa không khai báo rõ ràng một serialVersionUID, sau đó thời gian chạy tuần tự hóa sẽ tính toán một giá trị serialVersionUID mặc định cho lớp đó dựa trên các khía cạnh khác nhau của lớp, như được mô tả trong Đặc tả tuần tự hóa đối tượng Java (TM). Tuy nhiên, chúng tôi đặc biệt khuyến nghị rằng tất cả các lớp tuần tự hóa đều khai báo rõ ràng các giá trị serialVersionUID, vì tính toán serialVersionUID mặc định rất nhạy cảm với các chi tiết lớp có thể thay đổi tùy theo việc triển khai trình biên dịch và do đó có thể dẫn đến các lỗi không mong muốn trong quá trình khử lưu huỳnh. Do đó, để đảm bảo giá trị serialVersionUID nhất quán trong các triển khai trình biên dịch java khác nhau, một lớp tuần tự hóa phải khai báo một giá trị serialVersionUID rõ ràng. Chúng tôi cũng khuyên rằng các khai báo serialVersionUID rõ ràng nên sử dụng công cụ sửa đổi riêng nếu có thể,

Nếu bạn nhận thấy có một từ khóa khác, chúng tôi đã sử dụng đó là tạm thời .

Nếu một trường không được tuần tự hóa, nó phải được đánh dấu thoáng qua. Ở đây, chúng tôi đã đánh dấu itemCostprice là tạm thời và không muốn nó được ghi trong một tệp

Bây giờ chúng ta hãy xem làm thế nào để viết trạng thái của một đối tượng trong tệp và sau đó đọc nó từ đó.

public class SerializationExample {

    public static void main(String[] args){
        serialize();
       deserialize();
    } 

    public static void serialize(){

         Item item = new Item(1L,"Pen", 12.55);
         System.out.println("Before Serialization" + item);

         FileOutputStream fileOut;
         try {
             fileOut = new FileOutputStream("/tmp/item.ser");
             ObjectOutputStream out = new ObjectOutputStream(fileOut);
             out.writeObject(item);
             out.close();
             fileOut.close();
             System.out.println("Serialized data is saved in /tmp/item.ser");
           } catch (FileNotFoundException e) {

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

                  e.printStackTrace();
           }
      }

    public static void deserialize(){
        Item item;

        try {
                FileInputStream fileIn = new FileInputStream("/tmp/item.ser");
                ObjectInputStream in = new ObjectInputStream(fileIn);
                item = (Item) in.readObject();
                System.out.println("Serialized data is read from /tmp/item.ser");
                System.out.println("After Deserialization" + item);
        } catch (FileNotFoundException e) {
                e.printStackTrace();
        } catch (IOException e) {
               e.printStackTrace();
        } catch (ClassNotFoundException e) {
               e.printStackTrace();
        }
     }
}

Trong phần trên chúng ta có thể thấy một ví dụ về tuần tự hóa và giải tuần tự hóa một đối tượng.

Cho rằng chúng tôi đã sử dụng hai lớp. Để tuần tự hóa đối tượng, chúng tôi đã sử dụng ObjectOutputStream. Chúng tôi đã sử dụng phương thức writeObject để ghi đối tượng trong tệp.

Để Deserializing, chúng tôi đã sử dụng ObjectInputStream để đọc từ đối tượng từ tệp. Nó sử dụng readObject để đọc dữ liệu đối tượng từ tệp.

Đầu ra của đoạn mã trên sẽ như sau:

Before SerializationItem [itemId=1, itemName=Pen, itemCostPrice=12.55]
Serialized data is saved in /tmp/item.ser
After DeserializationItem [itemId=1, itemName=Pen, itemCostPrice=null]

Lưu ý rằng itemCostprice từ đối tượng deserialized là null vì nó không được viết.

Chúng ta đã thảo luận về những điều cơ bản của Tuần tự hóa Java trong phần I của bài viết này.

Bây giờ hãy thảo luận sâu sắc và làm thế nào nó hoạt động.

Trước tiên hãy bắt đầu với serialversionuid.

Các serialVersionUID được sử dụng như một điều khiển phiên bản trong một lớp Serializable.

Nếu bạn không khai báo rõ ràng một serialVersionUID, JVM sẽ tự động làm điều đó cho bạn, dựa trên các thuộc tính khác nhau của lớp Nối tiếp.

Thuật toán tính toán serialversionu của Java (Đọc thêm chi tiết tại đây)

  1. Tên lớp.
    1. Các bộ sửa đổi lớp được viết dưới dạng một số nguyên 32 bit.
    2. Tên của mỗi giao diện được sắp xếp theo tên.
    3. Đối với mỗi trường của lớp được sắp xếp theo tên trường (ngoại trừ trường tĩnh riêng và trường tạm thời riêng tư: Tên của trường. Công cụ sửa đổi của trường được viết dưới dạng số nguyên 32 bit. Mô tả của trường.
    4. Nếu một trình khởi tạo lớp tồn tại, hãy viết ra như sau: Tên của phương thức ,.
    5. Công cụ sửa đổi của phương thức, java.lang.reflect.Modifier.STATIC, được viết dưới dạng số nguyên 32 bit.
    6. Mô tả của phương thức, () V.
    7. Đối với mỗi hàm tạo không riêng được sắp xếp theo tên phương thức và chữ ký: Tên của phương thức ,. Các sửa đổi của phương thức được viết dưới dạng một số nguyên 32 bit. Các mô tả của phương pháp.
    8. Đối với mỗi phương thức không riêng được sắp xếp theo tên phương thức và chữ ký: Tên của phương thức. Các sửa đổi của phương thức được viết dưới dạng một số nguyên 32 bit. Các mô tả của phương pháp.
    9. Thuật toán SHA-1 được thực thi trên luồng byte được tạo bởi DataOutputStream và tạo ra năm giá trị 32 bit sha [0..4]. Giá trị băm được tập hợp từ giá trị 32 bit thứ nhất và thứ hai của bản tóm tắt thông điệp SHA-1. Nếu kết quả của thông báo tiêu hóa, năm từ 32 bit H0 H1 H2 H3 H4, nằm trong một mảng gồm năm giá trị int có tên là sha, giá trị băm sẽ được tính như sau:
    long hash = ((sha[0] >>> 24) & 0xFF) |
>            ((sha[0] >>> 16) & 0xFF) << 8 |
>            ((sha[0] >>> 8) & 0xFF) << 16 |
>            ((sha[0] >>> 0) & 0xFF) << 24 |
>            ((sha[1] >>> 24) & 0xFF) << 32 |
>            ((sha[1] >>> 16) & 0xFF) << 40 |
>            ((sha[1] >>> 8) & 0xFF) << 48 |
>        ((sha[1] >>> 0) & 0xFF) << 56;

Thuật toán tuần tự hóa của Java

Thuật toán để tuần tự hóa một đối tượng được mô tả như dưới đây:
1. Nó viết ra siêu dữ liệu của lớp được liên kết với một thể hiện.
2. Nó đệ quy viết ra mô tả của siêu lớp cho đến khi tìm thấy java.lang.object .
3. Sau khi hoàn thành việc ghi thông tin siêu dữ liệu, nó sẽ bắt đầu với dữ liệu thực tế được liên kết với thể hiện. Nhưng lần này, nó bắt đầu từ siêu lớp trên cùng.
4. Nó đệ quy ghi dữ liệu liên quan đến thể hiện, bắt đầu từ lớp siêu lớp nhỏ nhất đến lớp có nguồn gốc nhất.

Những điều cần lưu ý:

  1. Các trường tĩnh trong một lớp không thể được tuần tự hóa.

    public class A implements Serializable{
         String s;
         static String staticString = "I won't be serializable";
    }
  2. Nếu serialversionuid khác trong lớp đọc, nó sẽ đưa ra một InvalidClassExceptionngoại lệ.

  3. Nếu một lớp thực hiện tuần tự hóa thì tất cả các lớp con của nó cũng sẽ được tuần tự hóa.

    public class A implements Serializable {....};
    
    public class B extends A{...} //also Serializable
  4. Nếu một lớp có một tham chiếu của một lớp khác, tất cả các tham chiếu phải được tuần tự hóa nếu không quá trình tuần tự hóa sẽ không được thực hiện. Trong trường hợp như vậy, NotSerializableException được ném vào thời gian chạy.

Ví dụ:

public class B{
     String s,
     A a; // class A needs to be serializable i.e. it must implement Serializable
}

1
'Tuần tự hóa là quá trình tuần tự hóa trạng thái của một đối tượng được biểu diễn và lưu trữ dưới dạng một chuỗi các byte' là vô nghĩa. Nếu serialVersionUIDkhác thì nó sẽ ném InvalidClassException, chứ không phải a ClassCastException. Không cần thiết phải lãng phí tất cả không gian đó để bảo vệ serialVersionUIDtính toán. Tài liệu được trích dẫn, ở độ dài quá mức, nhưng không được liên kết hoặc trích dẫn đúng. Quá nhiều lông tơ ở đây và quá nhiều lỗi.
Hầu tước Lorne

'Tuần tự hóa là quá trình tuần tự hóa' vẫn vô nghĩa.
Hầu tước Lorne

6

Tuần tự hóa là quá trình chuyển đổi trạng thái của đối tượng thành bit để có thể lưu trữ trên ổ cứng. Khi bạn giải tuần tự hóa cùng một đối tượng, nó sẽ giữ lại trạng thái của nó sau này. Nó cho phép bạn tạo lại các đối tượng mà không cần phải lưu các thuộc tính của các đối tượng bằng tay.

http://en.wikipedia.org/wiki/Serialization


"... để nó có thể được lưu trữ trên ổ cứng." Hoặc chuyển qua giao thức nhị phân.
Jim Anderson

4

Tuần tự hóa đối tượng Java

nhập mô tả hình ảnh ở đây

Serializationlà một cơ chế để biến đổi một đồ thị của các đối tượng Java thành một mảng byte để lưu trữ ( to disk file) hoặc truyền ( across a network), sau đó bằng cách sử dụng deserialization chúng ta có thể khôi phục lại đồ thị của các đối tượng. Đồ thị của các đối tượng được khôi phục chính xác bằng cách sử dụng cơ chế chia sẻ tham chiếu. Nhưng trước khi lưu trữ, hãy kiểm tra xem serialVersionUID từ tệp đầu vào / mạng và tệp. Class serialVersionUID có giống nhau không. Nếu không, ném a java.io.InvalidClassException.

Mỗi lớp được phiên bản phải xác định phiên bản lớp gốc mà nó có khả năng viết các luồng và từ đó nó có thể đọc được. Ví dụ, một lớp được phiên bản phải khai báo:

Cú pháp nối tiếpVersionUID

// ANY-ACCESS-MODIFIER static final long serialVersionUID = (64-bit has)L;
private static final long serialVersionUID = 3487495895819393L;

serialVersionUID rất cần thiết cho quá trình tuần tự hóa. Nhưng nó là tùy chọn cho nhà phát triển để thêm nó vào tệp nguồn java. Nếu không bao gồm serialVersionUID, bộ thực thi tuần tự hóa sẽ tạo ra serialVersionUID và liên kết nó với lớp. Đối tượng được tuần tự hóa sẽ chứa serialVersionUID này cùng với các dữ liệu khác.

Lưu ý - Chúng tôi đặc biệt khuyến nghị rằng tất cả các lớp tuần tự hóa đều khai báo serialVersionUID một cách rõ ràng since the default serialVersionUID computation is highly sensitive to class details that may vary depending on compiler implementationsvà do đó có thể dẫn đến xung đột serialVersionUID bất ngờ trong quá trình khử lưu huỳnh, khiến quá trình khử lưu huỳnh không thành công.

Kiểm tra các lớp tuần tự

nhập mô tả hình ảnh ở đây


Một đối tượng Java chỉ được tuần tự hóa. nếu một lớp hoặc bất kỳ siêu lớp nào của nó thực hiện giao diện java.io.Serializable hoặc giao diện con của nó, java.io.Externalizable .

  • Một lớp phải thực hiện giao diện java.io.Serializable để tuần tự hóa thành công đối tượng của nó. Serializable là một giao diện đánh dấu và được sử dụng để thông báo cho trình biên dịch rằng lớp thực hiện nó phải được thêm hành vi tuần tự hóa. Ở đây Máy ảo Java (JVM) chịu trách nhiệm cho việc tuần tự hóa tự động của nó.

    Từ khóa thoáng qua: java.io.Serializable interface

    Trong khi tuần tự hóa một đối tượng, nếu chúng ta không muốn các thành viên dữ liệu nhất định của đối tượng được tuần tự hóa, chúng ta có thể sử dụng công cụ sửa đổi nhất thời. Từ khóa thoáng qua sẽ ngăn thành viên dữ liệu đó được tuần tự hóa.

    • Các trường được khai báo là tạm thời hoặc tĩnh được bỏ qua bởi quá trình tuần tự hóa.

    TRUYỀN THÔNG & TỰ ĐỘNG

    +--------------+--------+-------------------------------------+
    |  Flag Name   |  Value | Interpretation                      |
    +--------------+--------+-------------------------------------+
    | ACC_VOLATILE | 0x0040 | Declared volatile; cannot be cached.|
    +--------------+--------+-------------------------------------+
    |ACC_TRANSIENT | 0x0080 | Declared transient; not written or  |
    |              |        | read by a persistent object manager.|
    +--------------+--------+-------------------------------------+
    class Employee implements Serializable {
        private static final long serialVersionUID = 2L;
        static int id;
    
        int eno; 
        String name;
        transient String password; // Using transient keyword means its not going to be Serialized.
    }
  • Việc thực hiện giao diện Bên ngoài cho phép đối tượng nắm quyền kiểm soát hoàn toàn nội dung và định dạng của biểu mẫu nối tiếp của đối tượng. Các phương thức của giao diện ngoài, writeExternal và readExternal, được gọi để lưu và khôi phục trạng thái đối tượng. Khi được thực hiện bởi một lớp, họ có thể viết và đọc trạng thái của chính họ bằng cách sử dụng tất cả các phương thức của ObjectOutput và ObjectInput. Trách nhiệm của các đối tượng là xử lý bất kỳ phiên bản nào xảy ra.

    class Emp implements Externalizable {
        int eno; 
        String name;
        transient String password; // No use of transient, we need to take care of write and read.
    
        @Override
        public void writeExternal(ObjectOutput out) throws IOException {
            out.writeInt(eno);
            out.writeUTF(name);
            //out.writeUTF(password);
        }
        @Override
        public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
            this.eno = in.readInt();
            this.name = in.readUTF();
            //this.password = in.readUTF(); // java.io.EOFException
        }
    }
  • Chỉ các đối tượng hỗ trợ giao diện java.io.Serializable hoặc java.io.Externalizable mới có thể là written to/read from stream. Lớp của mỗi đối tượng tuần tự hóa được mã hóa bao gồm tên lớp và chữ ký của lớp, các giá trị của các trường và mảng của đối tượng và đóng của bất kỳ đối tượng nào khác được tham chiếu từ các đối tượng ban đầu.

Ví dụ nối tiếp cho tập tin

public class SerializationDemo {
    static String fileName = "D:/serializable_file.ser";

    public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException {
        Employee emp = new Employee( );
        Employee.id = 1; // Can not Serialize Class data.
        emp.eno = 77;
        emp.name = "Yash";
        emp.password = "confidential";
        objects_WriteRead(emp, fileName);

        Emp e = new Emp( );
        e.eno = 77;
        e.name = "Yash";
        e.password = "confidential";
        objects_WriteRead_External(e, fileName);

        /*String stubHost = "127.0.0.1";
        Integer anyFreePort = 7777;
        socketRead(anyFreePort); //Thread1
        socketWrite(emp, stubHost, anyFreePort); //Thread2*/

    }
    public static void objects_WriteRead( Employee obj, String serFilename ) throws IOException{
        FileOutputStream fos = new FileOutputStream( new File( serFilename ) );
        ObjectOutputStream objectOut = new ObjectOutputStream( fos );
        objectOut.writeObject( obj );
        objectOut.close();
        fos.close();

        System.out.println("Data Stored in to a file");

        try {
            FileInputStream fis = new FileInputStream( new File( serFilename ) );
            ObjectInputStream ois = new ObjectInputStream( fis );
            Object readObject;
            readObject = ois.readObject();
            String calssName = readObject.getClass().getName();
            System.out.println("Restoring Class Name : "+ calssName); // InvalidClassException

            Employee emp = (Employee) readObject;
            System.out.format("Obj[No:%s, Name:%s, Pass:%s]", emp.eno, emp.name, emp.password);

            ois.close();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
    public static void objects_WriteRead_External( Emp obj, String serFilename ) throws IOException {
        FileOutputStream fos = new FileOutputStream(new File( serFilename ));
        ObjectOutputStream objectOut = new ObjectOutputStream( fos );

        obj.writeExternal( objectOut );
        objectOut.flush();

        fos.close();

        System.out.println("Data Stored in to a file");

        try {
            // create a new instance and read the assign the contents from stream.
            Emp emp = new Emp();

            FileInputStream fis = new FileInputStream(new File( serFilename ));
            ObjectInputStream ois = new ObjectInputStream( fis );

            emp.readExternal(ois);

            System.out.format("Obj[No:%s, Name:%s, Pass:%s]", emp.eno, emp.name, emp.password);

            ois.close();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

Ví dụ nối tiếp qua mạng

Phân phối trạng thái của đối tượng trên các không gian địa chỉ khác nhau, trong các quy trình khác nhau trên cùng một máy tính hoặc thậm chí trong nhiều máy tính được kết nối qua mạng, nhưng hoạt động cùng nhau bằng cách chia sẻ dữ liệu và gọi phương thức.

/**
 * Creates a stream socket and connects it to the specified port number on the named host. 
 */
public static void socketWrite(Employee objectToSend, String stubHost, Integer anyFreePort) {
    try { // CLIENT - Stub[marshalling]
        Socket client = new Socket(stubHost, anyFreePort);
        ObjectOutputStream out = new ObjectOutputStream(client.getOutputStream());
        out.writeObject(objectToSend);
        out.flush();
        client.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}
// Creates a server socket, bound to the specified port. 
public static void socketRead(  Integer anyFreePort ) {
    try { // SERVER - Stub[unmarshalling ]
        ServerSocket serverSocket = new ServerSocket( anyFreePort );
        System.out.println("Server serves on port and waiting for a client to communicate");
            /*System.in.read();
            System.in.read();*/

        Socket socket = serverSocket.accept();
        System.out.println("Client request to communicate on port server accepts it.");

        ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
        Employee objectReceived = (Employee) in.readObject();
        System.out.println("Server Obj : "+ objectReceived.name );

        socket.close();
        serverSocket.close();
    } catch (IOException | ClassNotFoundException e) {
        e.printStackTrace();
    }
}

@xem


1
Khi bạn thêm một câu trả lời cho một câu hỏi sáu năm tuổi đã có một số câu trả lời rất hay, bạn cần phải làm tốt hơn rất nhiều so với một lỗi chính tả.
Hầu tước Lorne

@ejp Downvote là công cụ để bày tỏ ý kiến ​​tiêu cực của bạn. Bị xúc phạm và thô lỗ biên giới là không thể chấp nhận.
Konstantinos Chertouras

1
@KonstantinosChertouras Đưa ra lý do cho downvote là hữu ích cho người đăng, và đó là những lý do của tôi, giống như họ hay không như bạn muốn.
Hầu tước Lorne

Bạn cũng cần tránh các lỗi như khẳng định rằng Tuần tự hóa có mục đích bảo mật. Nó không.
Hầu tước Lorne

@EJP Tôi đã cập nhật bài đăng của mình, đã sửa rằng Tuần tự hóa không nhằm mục đích bảo mật, nhưng nó được sử dụng để chuyển đổi trạng thái của Đối tượng thành bất kỳ Lưu trữ nào và để lấy lại trạng thái ban đầu của một đối tượng bằng SUID thông qua cơ chế khử lưu huỳnh. JVM to JVM
Yash

3

Tuần tự hóa là quá trình lưu một đối tượng trong một phương tiện lưu trữ (chẳng hạn như tệp hoặc bộ nhớ đệm) hoặc để truyền nó qua kết nối mạng ở dạng nhị phân. Các đối tượng được tuần tự hóa là độc lập JVM và có thể được tuần tự hóa lại bởi bất kỳ JVM nào. Trong trường hợp này, trạng thái đối tượng java "trong bộ nhớ" được chuyển đổi thành một luồng byte. Người dùng không thể hiểu loại tập tin này. Nó là một loại đối tượng đặc biệt, tức là được sử dụng lại bởi JVM (Máy ảo Java). Quá trình tuần tự hóa một đối tượng này còn được gọi là xì hơi hoặc sắp xếp một đối tượng.

Các đối tượng được tuần tự hóa phải thực hiện java.io.SerializableGiao diện. Cơ chế tuần tự hóa mặc định cho một đối tượng ghi lớp của đối tượng, chữ ký lớp và các giá trị của tất cả các trường không tạm thời và không tĩnh.

class ObjectOutputStream extends java.io.OutputStream implements ObjectOutput,

ObjectOutputgiao diện mở rộng DataOutputgiao diện và thêm các phương thức để tuần tự hóa các đối tượng và ghi byte vào tệp. Các ObjectOutputStreammở rộng java.io.OutputStreamvà thực hiện ObjectOutput giao diện. Nó tuần tự hóa các đối tượng, mảng và các giá trị khác thành một luồng. Do đó, constructor của ObjectOutputStreamđược viết là:

ObjectOutput ObjOut = new ObjectOutputStream(new FileOutputStream(f));

Đoạn mã trên đã được sử dụng để tạo thể hiện của ObjectOutputlớp với hàm ObjectOutputStream( )tạo lấy ví dụ của FileOuputStreamtham số làm tham số.

Các ObjectOutputgiao diện được sử dụng bằng cách thực hiện các ObjectOutputStreamlớp. Các ObjectOutputStreamđược xây dựng để serialize đối tượng.

Giải trừ một đối tượng trong java

Hoạt động ngược lại của tuần tự hóa được gọi là giải tuần tự hóa, nghĩa là trích xuất dữ liệu từ một chuỗi các byte được gọi là giải tuần tự hóa còn được gọi là lạm phát hoặc không sắp xếp.

ObjectInputStreammở rộng java.io.InputStreamvà thực hiện ObjectInput giao diện. Nó giải tuần tự hóa các đối tượng, mảng và các giá trị khác từ luồng đầu vào. Do đó, constructor của ObjectInputStreamđược viết là:

ObjectInputStream obj = new ObjectInputStream(new FileInputStream(f));

Mã ở trên của chương trình tạo ra thể hiện của ObjectInputStreamlớp để giải tuần tự hóa tệp đó đã được tuần tự hóa bởi ObjectInputStreamlớp. Đoạn mã trên tạo ra thể hiện bằng cách sử dụng thể hiện của FileInputStreamlớp chứa đối tượng tệp đã chỉ định phải được giải tuần tự hóa bởi vì hàm ObjectInputStream()tạo cần luồng đầu vào.


2

Tuần tự hóa là quá trình biến một đối tượng Java thành mảng byte và sau đó trở lại thành đối tượng với trạng thái được bảo toàn. Hữu ích cho những thứ khác nhau như gửi các đối tượng qua mạng hoặc lưu trữ mọi thứ vào đĩa.

Đọc thêm từ bài viết ngắn này giải thích phần lập trình của quá trình khá tốt và sau đó chuyển sang javadoc nối tiếp . Bạn cũng có thể quan tâm đến việc đọc câu hỏi liên quan này .


2

Trả lại tệp dưới dạng Đối tượng: http://www.tutorialspoint.com/java/java_serialization.htmlm

        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();
              }
           }
        }

    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);
        }
    }

Điều này không trả lời các phần 'là gì' hoặc 'vui lòng giải thích' các câu hỏi.
Hầu tước Lorne

1

| * | Tuần tự hóa một lớp: Chuyển đổi một đối tượng thành byte và byte trở lại đối tượng (Deserialization).

class NamCls implements Serializable
{
    int NumVar;
    String NamVar;
}

| => Nối tiếp đối tượng là quá trình chuyển đổi trạng thái của đối tượng thành hơi byte.

  • | -> Thực hiện khi bạn muốn đối tượng tồn tại ngoài vòng đời của JVM.
  • | -> Đối tượng nối tiếp có thể được lưu trữ trong Cơ sở dữ liệu.
  • | -> Các đối tượng nối tiếp không thể được đọc và hiểu bởi con người để chúng ta có thể đạt được bảo mật.

| => Object-Deserialization là quá trình lấy trạng thái của một đối tượng và lưu trữ nó vào một đối tượng (java.lang.Object).

  • | -> Trước khi lưu trữ trạng thái của nó, nó kiểm tra xem serialVersionUID có dạng tệp đầu vào / mạng và tệp. Class serialVersionUID có giống nhau không.
    & nbsp & nbspNếu không ném java.io.InvalidClassException.

| => Một đối tượng Java chỉ được tuần tự hóa, nếu lớp của nó hoặc bất kỳ siêu lớp nào của nó

  • thực hiện giao diện java.io.Serializable hoặc
  • giao diện con của nó, java.io.Externalizable.

| => Các trường tĩnh trong một lớp không thể được tuần tự hóa.

class NamCls implements Serializable
{
    int NumVar;
    static String NamVar = "I won't be serializable";;
}

| => Nếu bạn không muốn tuần tự hóa một biến của một lớp sử dụng từ khóa thoáng qua

class NamCls implements Serializable
{
    int NumVar;
    transient String NamVar;
}

| => Nếu một lớp thực hiện tuần tự hóa thì tất cả các lớp con của nó cũng sẽ được tuần tự hóa.

| => Nếu một lớp có tham chiếu của một lớp khác, tất cả các tham chiếu phải là Tuần tự hóa nếu không quá trình tuần tự hóa sẽ không được thực hiện. Trong trường hợp như vậy,
NotSerializableException được ném vào thời gian chạy.


0

Tôi sẽ đưa ra một sự tương tự để có khả năng hỗ trợ trong việc củng cố mục đích khái niệm / tính thực tiễn của việc tuần tự hóa / giải tuần tự hóa đối tượng .

Tôi tưởng tượng tuần tự hóa / giải tuần tự hóa đối tượng trong bối cảnh cố gắng di chuyển một đối tượng qua một cơn bão. Đối tượng về cơ bản là "bị phân tách" hoặc được xê-ri hóa thành các phiên bản mô đun hơn của chính nó - trong trường hợp này là một chuỗi các byte - để có hiệu quả được cấp thông qua một phương tiện. Theo nghĩa tính toán, chúng ta có thể xem đường đi của các byte thông qua cống thoát bão giống như các byte truyền qua mạng. Chúng tôi đang chuyển đổi đối tượng của mình để tuân thủ một chế độ vận chuyển hoặc định dạng mong muốn hơn. Đối tượng được tuần tự hóa thường sẽ được lưu trữ trong một tệp nhị phân mà sau này có thể được đọc từ, ghi vào hoặc cả hai.

Có lẽ một khi đối tượng của chúng ta có thể trượt qua cống như một chuỗi byte bị phân tách, chúng ta có thể muốn lưu trữ biểu diễn đó của đối tượng dưới dạng dữ liệu nhị phân trong cơ sở dữ liệu hoặc ổ đĩa cứng. Mặc dù vậy, điều đáng nói chính là với việc tuần tự hóa / giải tuần tự hóa, chúng ta có tùy chọn để cho đối tượng của mình ở dạng nhị phân sau khi được tuần tự hóa hoặc "lấy lại" hình thức ban đầu của đối tượng bằng cách thực hiện khử lưu huỳnh.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.