คลาสที่อยู่Serializable
ใน Java หมายความว่าอย่างไร หรือโดยทั่วไปสำหรับเรื่องนั้น ...
คลาสที่อยู่Serializable
ใน Java หมายความว่าอย่างไร หรือโดยทั่วไปสำหรับเรื่องนั้น ...
คำตอบ:
Serializationคือการคงออบเจ็กต์จากหน่วยความจำไปยังลำดับของบิตตัวอย่างเช่นการบันทึกลงในดิสก์ Deserialization ตรงกันข้าม - การอ่านข้อมูลจากดิสก์เพื่อไฮเดรต / สร้างวัตถุ
ในบริบทของคำถามของคุณเป็นอินเทอร์เฟซที่หากนำไปใช้ในคลาสคลาสนี้สามารถต่ออนุกรมและแยกส่วนโดยอัตโนมัติโดย serializers ที่แตกต่างกัน
แม้ว่าผู้ใช้ส่วนใหญ่จะให้คำตอบไปแล้ว แต่ฉันอยากจะเพิ่มตัวอย่างสำหรับผู้ที่ต้องการเพื่ออธิบายแนวคิด:
สมมติว่าคุณมีบุคคลในชั้นเรียนดังต่อไปนี้:
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);
}
}
จากนั้นคุณสร้างวัตถุดังนี้:
Person william = new Person();
william.firstName = "William";
william.lastName = "Kinaan";
william.age = 26;
william.address = "Lisbon, Portugal";
คุณสามารถต่ออนุกรมวัตถุนั้นกับหลายสตรีม ฉันจะทำแบบนั้นกับสองสตรีม:
การทำให้เป็นอนุกรมกับเอาต์พุตมาตรฐาน:
public static void serializeToStandardOutput(Person person)
throws IOException {
OutputStream outStream = System.out;
ObjectOutputStream stdObjectOut = new ObjectOutputStream(outStream);
stdObjectOut.writeObject(person);
stdObjectOut.close();
outStream.close();
}
การทำให้เป็นอนุกรมกับไฟล์:
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();
}
จากนั้น:
Deserialize จากไฟล์:
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();
}
หมายความว่าอินสแตนซ์ของคลาสสามารถเปลี่ยนเป็นไบต์สตรีม (ตัวอย่างเช่นเพื่อบันทึกลงไฟล์) จากนั้นแปลงกลับเป็นคลาสอีกครั้ง การโหลดซ้ำนี้อาจเกิดขึ้นในอินสแตนซ์อื่นของโปรแกรมหรือแม้กระทั่งในเครื่องอื่น การทำให้เป็นอนุกรม (ในภาษาใดก็ได้) เกี่ยวข้องกับปัญหาทุกประเภทโดยเฉพาะอย่างยิ่งเมื่อคุณได้รับการอ้างอิงไปยังวัตถุอื่น ๆ ในซีเรียลที่สามารถใช้งานได้
นี่คือคำอธิบายโดยละเอียดของ Serialization : (บล็อกของฉันเอง)
การทำให้เป็นอนุกรม:
การทำให้เป็นอนุกรมเป็นกระบวนการในการทำให้เป็นอนุกรมสถานะของวัตถุจะถูกแสดงและจัดเก็บในรูปแบบของลำดับไบต์ สิ่งนี้สามารถเก็บไว้ในไฟล์ กระบวนการอ่านสถานะของอ็อบเจ็กต์จากไฟล์และเรียกคืนเรียกว่า deserialization
ความต้องการของ Serialization คืออะไร?
ในสถาปัตยกรรมสมัยใหม่มีความจำเป็นที่จะต้องจัดเก็บสถานะของวัตถุแล้วเรียกคืนเสมอ ตัวอย่างเช่นใน Hibernate ในการจัดเก็บวัตถุเราควรทำให้คลาส Serial ได้ สิ่งที่ทำก็คือเมื่อสถานะอ็อบเจ็กต์ถูกบันทึกในรูปแบบของไบต์มันสามารถโอนไปยังระบบอื่นซึ่งสามารถอ่านจากสถานะและดึงคลาสได้ สถานะออบเจ็กต์อาจมาจากฐานข้อมูลหรือ jvm อื่นหรือจากคอมโพเนนต์แยกต่างหาก ด้วยความช่วยเหลือของ Serialization เราสามารถดึงสถานะ Object ได้
ตัวอย่างโค้ดและคำอธิบาย:
ก่อนอื่นมาดู Item Class กันก่อน:
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;
}
}
ในโค้ดด้านบนจะเห็นได้ว่าคลาสไอเท็มใช้Serialได้
นี่คืออินเทอร์เฟซที่ช่วยให้คลาสสามารถต่ออนุกรมกันได้
ตอนนี้เราสามารถเห็นตัวแปรที่เรียกว่าserialVersionUIDเริ่มต้นเป็นตัวแปร Long ตัวเลขนี้คำนวณโดยคอมไพลเลอร์ตามสถานะของคลาสและแอ็ตทริบิวต์คลาส นี่คือตัวเลขที่จะช่วยให้ jvm ระบุสถานะของวัตถุเมื่อมันอ่านสถานะของวัตถุจากไฟล์
สำหรับสิ่งนั้นเราสามารถดูเอกสาร Oracle อย่างเป็นทางการ:
รันไทม์การทำให้เป็นอนุกรมเชื่อมโยงกับแต่ละคลาสที่ทำให้เป็นหมายเลขเวอร์ชันเรียกว่า serialVersionUID ซึ่งใช้ในระหว่างการดีซีเรียลไลเซชันเพื่อตรวจสอบว่าผู้ส่งและผู้รับของอ็อบเจ็กต์ที่ทำให้เป็นอนุกรมได้โหลดคลาสสำหรับอ็อบเจ็กต์นั้นที่เข้ากันได้กับการทำให้เป็นอนุกรม ถ้าผู้รับโหลดคลาสสำหรับอ็อบเจ็กต์ที่มี serialVersionUID แตกต่างจากคลาสของผู้ส่งที่เกี่ยวข้องการ deserialization จะทำให้ InvalidClassException คลาสที่ทำให้เป็นอนุกรมสามารถประกาศ serialVersionUID ของตัวเองได้อย่างชัดเจนโดยการประกาศฟิลด์ชื่อ "serialVersionUID" ที่ต้องเป็นแบบคงที่สุดท้ายและประเภทยาว: ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L; ถ้าคลาสที่ทำให้เป็นอนุกรมไม่ได้ประกาศ serialVersionUID อย่างชัดเจน จากนั้นรันไทม์การทำให้เป็นอนุกรมจะคำนวณค่า serialVersionUID ดีฟอลต์สำหรับคลาสนั้นตามลักษณะต่างๆของคลาสตามที่อธิบายไว้ใน Java (TM) Object Serialization Specification อย่างไรก็ตามขอแนะนำอย่างยิ่งว่าคลาสที่ทำให้เป็นอนุกรมได้ทั้งหมดต้องประกาศค่า serialVersionUID อย่างชัดเจนเนื่องจากการคำนวณ serialVersionUID เริ่มต้นมีความอ่อนไหวอย่างมากต่อรายละเอียดของคลาสที่อาจแตกต่างกันไปขึ้นอยู่กับการใช้งานคอมไพลเลอร์และอาจส่งผลให้ InvalidClassExceptions ที่ไม่คาดคิดในระหว่างการ deserialization ดังนั้นเพื่อรับประกันค่า serialVersionUID ที่สอดคล้องกันในการใช้งานคอมไพเลอร์ java ที่แตกต่างกันคลาสที่ทำให้เป็นอนุกรมได้ต้องประกาศค่า serialVersionUID อย่างชัดเจน ขอแนะนำอย่างยิ่งว่าการประกาศ serialVersionUID อย่างชัดเจนให้ใช้ตัวปรับแต่งส่วนตัวหากเป็นไปได้
ถ้าคุณได้สังเกตเห็นมีคำหลักอื่นที่เราได้ใช้ซึ่งเป็นชั่วคราว
หากฟิลด์ไม่สามารถทำให้เป็นอนุกรมได้จะต้องทำเครื่องหมายชั่วคราว ที่นี่เราทำเครื่องหมายitemCostPriceเป็นชั่วคราวและไม่ต้องการให้เขียนลงในไฟล์
ตอนนี้เรามาดูวิธีการเขียนสถานะของวัตถุในไฟล์แล้วอ่านจากที่นั่น
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();
}
}
}
ในข้างต้นเราจะเห็นตัวอย่างของการทำให้เป็นอนุกรมและการดีซีเรียลไลเซชันของวัตถุ
เพราะเราใช้สองคลาส สำหรับการทำให้เป็นอนุกรมวัตถุเราได้ใช้ ObjectOutputStream เราได้ใช้เมธอด writeObject เพื่อเขียนอ็อบเจกต์ในไฟล์
สำหรับ Deserializing เราได้ใช้ ObjectInputStream ซึ่งอ่านจากวัตถุจากไฟล์ ใช้ readObject เพื่ออ่านข้อมูลวัตถุจากไฟล์
ผลลัพธ์ของโค้ดด้านบนจะเป็นดังนี้:
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]
สังเกตว่าitemCostPriceจาก deserialized object เป็นโมฆะเนื่องจากไม่ได้เขียน
การทำให้เป็นอนุกรมเกี่ยวข้องกับการบันทึกสถานะปัจจุบันของอ็อบเจ็กต์ไปยังสตรีมและการกู้คืนอ็อบเจ็กต์ที่เทียบเท่าจากสตรีมนั้น สตรีมทำหน้าที่เป็นคอนเทนเนอร์สำหรับอ็อบเจ็กต์
Serializable ถูกเรียกในเหมือนอินเทอร์เฟซ แต่คล้ายกับแฟล็กของระบบย่อย Serialization ที่รันไทม์ มันบอกว่าวัตถุนี้สามารถบันทึกได้ ตัวแปรอินสแตนซ์อ็อบเจ็กต์ทั้งหมดยกเว้นอ็อบเจ็กต์ที่ต่ออนุกรมได้และอ็อบเจ็กต์ที่ทำเครื่องหมายระเหยจะถูกบันทึก
ลองนึกภาพแอปพลิเคชันของคุณสามารถเปลี่ยนสีเป็นตัวเลือกได้โดยไม่ต้องเก็บการตั้งค่านั้นไว้ภายนอกคุณจะต้องเปลี่ยนสีทุกครั้งที่ใช้งาน
Serialization เป็นเทคนิคในการจัดเก็บหรือเขียนวัตถุและข้อมูลลงในไฟล์ โดยใช้ObjectOutputStream
และFileOutputStream
คลาส. คลาสเหล่านี้มีวิธีการเฉพาะในการคงอยู่ของวัตถุ ชอบwriteObject();
เพื่อการอธิบายที่ชัดเจนด้วยตัวเลข ดูที่นี่สำหรับข้อมูลเพิ่มเติม
เพื่อนำเสนอจากมุมมองอื่น Serialization คืออินเทอร์เฟซชนิดหนึ่งที่เรียกว่า 'marker interface' อินเทอร์เฟซ marker เป็นอินเทอร์เฟซที่ไม่มีการประกาศเมธอด แต่เพียงกำหนด (หรือ "เครื่องหมาย") คลาสที่ใช้อินเทอร์เฟซว่ามีคุณสมบัติบางอย่าง หากคุณเข้าใจความแตกต่างหลากหลายสิ่งนี้จะเข้าท่ามาก ในกรณีของอินเทอร์เฟซตัวทำเครื่องหมายที่ต่ออนุกรมได้เมธอด ObjectOutputStream.write (Object) จะล้มเหลวหากอาร์กิวเมนต์ไม่ได้ใช้อินเทอร์เฟซ นี่เป็นข้อผิดพลาดที่อาจเกิดขึ้นใน java ซึ่งอาจเป็น ObjectOutputStream.write (ต่อเนื่องได้)
แนะนำเป็นอย่างยิ่ง: อ่าน Item 37 จากEffective Java โดย Joshua Blochเพื่อเรียนรู้เพิ่มเติม
Serialization:การเขียนสถานะของวัตถุไปยังไฟล์ / เครือข่ายหรือที่ใดก็ได้ (หมายถึงรูปแบบที่รองรับ Java Object เป็น File Supported Form หรือ Network Supported Form)
Deserialization: การอ่านสถานะของวัตถุจากไฟล์ / เครือข่ายหรือที่ใดก็ได้ (หมายถึงไฟล์ / เครือข่ายที่รองรับรูปแบบกับ Java Object Supported Form)
เพียงเพื่อเพิ่มคำตอบอื่น ๆ และเกี่ยวกับลักษณะทั่วไป การทำให้เป็นอนุกรมบางครั้งเรียกว่าการเก็บถาวรเช่นใน 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.