Chính xác thì nó có nghĩa gì với một lớp Serializable
trong Java? Hay nói chung, cho vấn đề đó ...
Chính xác thì nó có nghĩa gì với một lớp Serializable
trong Java? Hay nói chung, cho vấn đề đó ...
Câu trả lời:
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.
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();
}
Đ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.
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.
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
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ó.
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 ObjectOutputStream
vàFileOutputStream
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
Để 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.
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)
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.
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.