Nối tiếp có nghĩa là gì?


136

Chính xác thì nó có nghĩa gì với một lớp Serializabletrong Java? Hay nói chung, cho vấn đề đó ...


10
@skaffman Đây là những gì nó nói cho lớp học Serializable: Serializability of a class is enabled by the class implementing the java.io.Serializable interface. Classes that do not implement this interface will not have any of their state serialized or deserialized. All subtypes of a serializable class are themselves serializable. The serialization interface has no methods or fields and serves only to identify the semantics of being serializable.
Ritwik Bose

32
Một lời giải thích tuyệt vời nếu bạn đã biết ý nghĩa nối tiếp và giải tuần tự hóa. (Không phải là một lời khen.) Các định nghĩa như vậy giúp bạn hiểu vấn đề tốt hơn về mặt kỹ thuật một lần và chỉ một lần, bạn đã có một số kiến ​​thức về nó.
Xonatron

Câu trả lời:


131

Tuần tự hóa đang duy trì một đối tượng từ bộ nhớ đến một chuỗi bit, ví dụ để lưu vào đĩa. Deserialization thì ngược lại - đọc dữ liệu từ đĩa để hydrat hóa / tạo một đối tượng.

Trong ngữ cảnh câu hỏi của bạn, đó là một giao diện mà nếu được triển khai trong một lớp, lớp này có thể tự động được tuần tự hóa và giải tuần tự hóa bởi các trình tuần tự khác nhau.


2
Cũng lưu ý rằng tất cả các trường không được đánh dấu rõ ràng nếu không cũng sẽ được tuần tự hóa. Điều này có nghĩa là bạn có thể lưu cơ sở hạ tầng phức tạp một cách dễ dàng chỉ bằng cách tuần tự hóa đối tượng gốc.
Thorbjørn Ravn Andersen

1
Vì vậy, khi chúng ta nói về "Đối tượng", chúng ta có nghĩa là đối tượng được khởi tạo bởi một lớp hay chỉ bất kỳ "Đối tượng phần mềm" nào như tập hợp, tệp, v.v.? Và nếu là cái sau, nó chỉ là một cách gửi dữ liệu được chuẩn hóa giữa các chương trình và môi trường?
Sunburst275

1
@ Sunburst275 - trong trường hợp này, đây là biểu diễn trong bộ nhớ của một lớp trong bộ nhớ - tức là một thể hiện của một lớp (không có điểm nào thực sự để nói về tuần tự hóa các cụm, vì chúng thường nằm trên đĩa dưới dạng các tệp có thể chỉ đơn giản là được gửi xung quanh như là).
Oded

43

Mặc dù hầu hết người dùng đã đưa ra câu trả lời, nhưng tôi muốn thêm một ví dụ cho những người cần nó để giải thích ý tưởng:

Giả sử bạn có một người đẳng cấp như sau:

public class Person implements java.io.Serializable {
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    public String firstName;
    public String lastName;
    public int age;
    public String address;

    public void play() {
        System.out.println(String.format(
                "If I win, send me the trophy to this address: %s", address));
    }
    @Override
    public String toString() {
        return String.format(".....Person......\nFirst Name = %s\nLast Name = %s", firstName, lastName);
    }
}

và sau đó bạn tạo một đối tượng như thế này:

Person william = new Person();
        william.firstName = "William";
        william.lastName = "Kinaan";
        william.age = 26;
        william.address = "Lisbon, Portugal";

Bạn có thể nối tiếp đối tượng đó với nhiều luồng. Tôi sẽ làm điều đó đến hai luồng:

Tuần tự hóa thành đầu ra tiêu chuẩn:

public static void serializeToStandardOutput(Person person)
            throws IOException {
        OutputStream outStream = System.out;
        ObjectOutputStream stdObjectOut = new ObjectOutputStream(outStream);
        stdObjectOut.writeObject(person);
        stdObjectOut.close();
        outStream.close();
    }

Tuần tự hóa thành một tập tin:

public static void serializeToFile(Person person) throws IOException {
        OutputStream outStream = new FileOutputStream("person.ser");
        ObjectOutputStream fileObjectOut = new ObjectOutputStream(outStream);
        fileObjectOut.writeObject(person);
        fileObjectOut.close();
        outStream.close();
    }

Sau đó:

Giải trừ khỏi tập tin:

public static void deserializeFromFile() throws IOException,
            ClassNotFoundException {
        InputStream inStream = new FileInputStream("person.ser");
        ObjectInputStream fileObjectIn = new ObjectInputStream(inStream);
        Person person = (Person) fileObjectIn.readObject();
        System.out.println(person);
        fileObjectIn.close();
        inStream.close();
    }

Cảm ơn bạn. Tôi nghĩ rằng tôi đã nhận nó ngay bây giờ.
Sunburst275

39

Điều đó có nghĩa là các thể hiện của lớp có thể được chuyển thành luồng byte (ví dụ: được lưu vào một tệp) và sau đó được chuyển đổi lại thành các lớp. Việc tải lại này có thể xảy ra trong một phiên bản khác của chương trình, hoặc thậm chí trên một máy khác. Tuy nhiên, tuần tự hóa (trong bất kỳ ngôn ngữ nào) liên quan đến tất cả các loại vấn đề, đặc biệt là khi bạn có các tham chiếu đến các đối tượng khác bên trong đối tượng nối tiếp.


14

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 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. Đ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.


2
Cảm ơn bạn đã giải thích chi tiết này.
Promise Preston

Đây là một lời giải thích tốt đẹp! Cảm ơn bạn! Nhưng thành thật mà nói, mục này trông sạch sẽ hơn nhiều so với mục trên blog của bạn. Dù sao, điều này đã giúp rất nhiều!
Sunburst275

11

Tuần tự hóa liên quan đến việc lưu trạng thái hiện tại của một đối tượng vào một luồng và khôi phục một đối tượng tương đương từ luồng đó. Luồng có chức năng như một thùng chứa cho đối tượng


1
Định nghĩa này có vẻ chính xác hơn. Cảm ơn bạn.
Promise Preston

6

Serializable được gọi trong giống như một giao diện nhưng nó giống như một cờ cho trình biên dịch. Nó nói đối tượng này có thể được lưu. Tất cả các biến đối tượng Đối tượng ngoại trừ không có đối tượng tuần tự hóa và các đối tượng đánh dấu biến động sẽ được lưu.

Hãy tưởng tượng ứng dụng của bạn có thể thay đổi màu sắc như một tùy chọn, mà không cần giữ cài đặt bên ngoài đó, bạn sẽ cần thay đổi màu mỗi khi bạn chạy nó.


5
Nó không phải là 'cờ cho trình biên dịch'. Nó là một cờ cho hệ thống con serialization, trong thời gian chạy.
Hầu tước Lorne

1
@EJP - Cảm ơn, không biết điều đó
AphexMunky

Với sự tôn trọng, tại sao lại viết nó khi bạn không biết nó là sự thật? Bạn cũng đã bỏ qua 'thoáng qua'. Tất cả trong một câu trả lời kém, xin lỗi.
Hầu tước Lorne

19
Nếu tôi không viết nó, tôi sẽ không được sửa chữa và sẽ tệ hơn. Tất cả các câu trả lời khác cũng đã để lại thoáng qua. Bạn thậm chí không viết một câu trả lời, bạn chỉ đang troll người khác.
AphexMunky

4

Tuần tự hóa là một kỹ thuật để lưu trữ hoặc ghi các đối tượng và dữ liệu vào tệp. Bằng cách sử dụng ObjectOutputStreamFileOutputStream các lớp học. Các lớp này có các phương thức cụ thể của chúng để duy trì các đối tượng. giốngwriteObject();

cho thám hiểm rõ ràng với số liệu. Xem ở đây để biết thêm


2

Để trình bày từ một quan điểm khác. Tuần tự hóa là một loại giao diện gọi là 'giao diện đánh dấu'. Giao diện đánh dấu là một giao diện không chứa khai báo phương thức, mà chỉ chỉ định (hoặc dấu mark Nhận) một lớp thực hiện giao diện là có một số thuộc tính. Nếu bạn hiểu đa hình thì điều này sẽ rất có ý nghĩa. Trong trường hợp giao diện đánh dấu Nối tiếp, phương thức ObjectOutputStream.write (Object) sẽ thất bại nếu đối số của nó không thực hiện giao diện. Đây là một lỗi tiềm ẩn trong java, nó có thể là ObjectOutputStream.write (Nối tiếp)

Rất khuyến khích: Đọc Mục 37 từ Java hiệu quả của Joshua Bloch để tìm hiểu thêm.


2

Tuần tự hóa: Viết trạng thái của đối tượng vào tệp / mạng hoặc bất cứ nơi nào. .

Deserialization: Reading State of Object từ File / Network hoặc bất cứ nơi nào. (Biểu mẫu được hỗ trợ tệp / mạng trung bình cho biểu mẫu được hỗ trợ đối tượng Java)


0

Chỉ để thêm vào các câu trả lời khác và liên quan đến tổng quát. Tuần tự hóa đôi khi được gọi là lưu trữ, ví dụ như trong Objective-C.

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.