"การทำให้เป็นอันดับวัตถุ" หมายถึงอะไร คุณช่วยอธิบายด้วยตัวอย่างได้ไหม
"การทำให้เป็นอันดับวัตถุ" หมายถึงอะไร คุณช่วยอธิบายด้วยตัวอย่างได้ไหม
คำตอบ:
การทำให้เป็นอันดับคือการแปลงวัตถุเป็นชุดของไบต์เพื่อให้วัตถุนั้นสามารถบันทึกได้อย่างง่ายดายไปยังที่เก็บข้อมูลถาวรหรือสตรีมผ่านการเชื่อมโยงการสื่อสาร สตรีมไบต์สามารถถูกดีซีเรียลไลซ์ - แปลงเป็นแบบจำลองของวัตถุดั้งเดิมได้
คุณสามารถคิดว่าการทำให้เป็นอันดับเป็นกระบวนการของการแปลงอินสแตนซ์ของวัตถุเป็นลำดับของไบต์ (ซึ่งอาจเป็นไบนารีหรือไม่ขึ้นอยู่กับการใช้งาน)
มันมีประโยชน์มากเมื่อคุณต้องการส่งข้อมูลวัตถุหนึ่งผ่านเครือข่ายเช่นจาก JVM หนึ่งไปยังอีก
ใน Java กลไกการทำให้เป็นอันดับจะถูกสร้างขึ้นในแพลตฟอร์ม แต่คุณต้องใช้ Serializableอินเตอร์เฟซที่จะทำให้วัตถุ serializable
คุณยังสามารถป้องกันข้อมูลบางอย่างในวัตถุของคุณจากการเป็นอนุกรมโดยการทำเครื่องหมายแอตทริบิวต์เป็น ชั่วคราว
ในที่สุดคุณสามารถแทนที่กลไกเริ่มต้นและจัดเตรียมของคุณเอง; นี่อาจเหมาะสมในบางกรณีพิเศษ เมื่อต้องการทำเช่นนี้คุณใช้อย่างใดอย่างหนึ่งคุณลักษณะที่ซ่อนอยู่ใน java
สิ่งสำคัญคือให้สังเกตว่าสิ่งที่ได้รับต่อเนื่องคือ "ค่า" ของวัตถุหรือเนื้อหาไม่ใช่ข้อกำหนดของคลาส ดังนั้นวิธีการจะไม่ต่อเนื่อง
นี่คือตัวอย่างพื้นฐานที่มีความคิดเห็นเพื่อช่วยในการอ่าน:
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();
}
}
เมื่อเรารันโปรแกรมนี้ไฟล์ "o.ser" จะถูกสร้างขึ้นและเราสามารถเห็นสิ่งที่เกิดขึ้นข้างหลัง
หากเราเปลี่ยนค่าเป็น: someIntegerเป็นตัวอย่างเช่นInteger.MAX_VALUEเราอาจเปรียบเทียบผลลัพธ์เพื่อดูว่าความแตกต่างคืออะไร
นี่คือภาพหน้าจอที่แสดงถึงความแตกต่างอย่างแม่นยำ:
คุณสามารถมองเห็นความแตกต่างได้หรือไม่? ;)
มีฟิลด์ที่เกี่ยวข้องเพิ่มเติมในการทำให้เป็นอันดับ Java คือ: serialversionUIDแต่ฉันเดาว่ามันยาวเกินไปที่จะครอบคลุม
SerializationSample
SerializationSample instance = new SerializationSample();
จากนั้นผลลัพธ์จะถูกสร้างขึ้นและวัตถุที่เขียนไปยังผลลัพธ์นั้น
กล้าที่จะตอบคำถามอายุ 6 ปีเพิ่มความเข้าใจในระดับสูงมากสำหรับผู้ที่เพิ่งเริ่มใช้ Java
การทำให้เป็นอันดับคืออะไร
การแปลงวัตถุเป็นไบต์
Deserialization คืออะไร
การแปลงไบต์กลับเป็นวัตถุ (Deserialization)
การใช้การทำให้เป็นอันดับเมื่อใด
เมื่อเราต้องการสานต่อวัตถุ เมื่อเราต้องการให้วัตถุมีอยู่เกินกว่าอายุการใช้งานของ JVM
ตัวอย่างโลกแห่งความจริง:
ATM: เมื่อเจ้าของบัญชีพยายามถอนเงินจากเซิร์ฟเวอร์ผ่าน ATM ข้อมูลเจ้าของบัญชีเช่นรายละเอียดการถอนจะถูกทำให้เป็นอนุกรมและส่งไปยังเซิร์ฟเวอร์ที่มีการแยกรายละเอียดและใช้ในการดำเนินการ
วิธีการทำให้เป็นอนุกรมในจาวา
ใช้java.io.Serializable
อินเตอร์เฟส (อินเทอร์เฟซตัวทำเครื่องหมายดังนั้นจึงไม่มีวิธีนำไปใช้)
คงวัตถุไว้: ใช้java.io.ObjectOutputStream
คลาสตัวกรองสตรีมซึ่งเป็น wrapper รอบ ๆ สตรีมไบต์ระดับต่ำกว่า (เพื่อเขียน Object ไปยังระบบไฟล์หรือถ่ายโอนวัตถุแบบแบนข้ามสายเครือข่ายและสร้างใหม่ในอีกด้านหนึ่ง)
writeObject(<<instance>>)
- เพื่อเขียนวัตถุ readObject()
- เพื่ออ่านออบเจ็กต์ที่ต่อเนื่องกันโปรดจำไว้ว่า:
เมื่อคุณทำให้วัตถุเป็นอนุกรมสถานะของวัตถุเท่านั้นที่จะถูกบันทึกไม่ใช่แฟ้มคลาสหรือวิธีการ
เมื่อคุณทำอนุกรมวัตถุ 2 ไบต์คุณจะเห็นไฟล์ที่จัดลำดับ 51 ไบต์
ขั้นตอนวิธีการทำให้วัตถุเป็นอนุกรมและไม่ต่อเนื่อง
คำตอบสำหรับ: มันแปลงเป็นไฟล์ 51 ไบต์ได้อย่างไร?
java.lang.Object
จนกว่าจะพบหากคุณสนใจข้อมูลเชิงลึกเกี่ยวกับ Java Serialization กรุณาตรวจสอบลิงค์นี้
แก้ไข : อีกหนึ่งลิงค์ที่ดีในการอ่าน
คำถามนี้จะตอบคำถามที่พบบ่อย:
วิธีที่จะไม่ต่อเนื่องเขตข้อมูลใด ๆ ในชั้นเรียน
ตอบ: ใช้คำค้นหาชั่วคราว
เมื่อคลาสย่อยถูกทำให้เป็นอนุกรมคลาสแม่จะได้รับการทำให้เป็นอนุกรมหรือไม่
ตอบ: ไม่หากผู้ปกครองไม่ได้ขยายฟิลด์ผู้ปกครองส่วนต่อประสานที่ปรับแต่งได้
เมื่อใดที่ผู้ปกครองได้รับการจัดลำดับคลาสเด็กจะได้รับการทำให้เป็นอนุกรมหรือไม่
คำตอบ: ใช่โดยค่าเริ่มต้นระดับลูกก็จะได้รับต่อเนื่อง
จะหลีกเลี่ยงชั้นเรียนของเด็กไม่ให้ต่อเนื่องได้อย่างไร
ตอบ: แทนที่ writeObject และ readObject NotSerializableException
วิธีการและโยน
ข นอกจากนี้คุณสามารถทำเครื่องหมายฟิลด์ทั้งหมดชั่วคราวในคลาสเด็ก
การทำให้เป็นอันดับคือการใช้วัตถุ "สด" ในหน่วยความจำและแปลงเป็นรูปแบบที่สามารถเก็บไว้ที่ไหนสักแห่ง (เช่นในหน่วยความจำบนดิสก์) และต่อมา "deserialized" กลับเป็นวัตถุสด
ฉันชอบวิธีที่ @OscarRyz นำเสนอ แม้ว่าที่นี่ฉันยังคงเรื่องราวของการทำให้เป็นอันดับซึ่งเขียนโดย @amitgupta
แม้ว่าการรู้เกี่ยวกับโครงสร้างคลาสของหุ่นยนต์และการมีข้อมูลที่เป็นอนุกรมนักวิทยาศาสตร์ของโลกก็ไม่สามารถกำจัดข้อมูลที่ทำให้หุ่นยนต์ทำงานได้
Exception in thread "main" java.io.InvalidClassException:
SerializeMe; local class incompatible: stream classdesc
:
นักวิทยาศาสตร์ของดาวอังคารกำลังรอการชำระเสร็จสมบูรณ์ เมื่อการชำระเงินเสร็จสิ้นนักวิทยาศาสตร์ของดาวอังคารได้แชร์serialversionUIDกับนักวิทยาศาสตร์ของโลก นักวิทยาศาสตร์ของโลกกำหนดให้คลาสหุ่นยนต์และทุกอย่างเรียบร้อยดี
การทำให้เป็นอนุกรมหมายถึงวัตถุที่ยังคงอยู่ใน java หากคุณต้องการบันทึกสถานะของวัตถุและต้องการสร้างสถานะใหม่ในภายหลัง (อาจอยู่ใน JVM อื่น) การทำให้เป็นอนุกรมสามารถใช้งานได้
โปรดทราบว่าคุณสมบัติของวัตถุจะถูกบันทึกไว้เท่านั้น ถ้าคุณต้องการที่จะคืนค่าวัตถุอีกครั้งคุณควรมีไฟล์คลาสเพราะตัวแปรสมาชิกเท่านั้นจะถูกเก็บไว้และไม่ใช่ฟังก์ชั่นสมาชิก
เช่น:
ObjectInputStream oos = new ObjectInputStream(
new FileInputStream( new File("o.ser")) ) ;
SerializationSample SS = (SearializationSample) oos.readObject();
Searializable เป็นอินเทอร์เฟซของตัวทำเครื่องหมายซึ่งระบุว่าคลาสของคุณเป็นแบบอนุกรม อินเทอร์เฟซตัวทำเครื่องหมายหมายความว่ามันเป็นเพียงอินเทอร์เฟซที่ว่างเปล่าและการใช้อินเทอร์เฟซนั้นจะแจ้งให้ JVM ทราบว่าคลาสนี้สามารถทำให้เป็นอนุกรมได้
My Two cents จากบล็อกของฉัน:
นี่คือคำอธิบายโดยละเอียดของการทำให้เป็นอันดับ : (บล็อกของฉันเอง)
อันดับ:
การทำให้เป็นอันดับเป็นกระบวนการของการคงสถานะของวัตถุ มันเป็นตัวแทนและเก็บไว้ในรูปแบบของลำดับของไบต์ สามารถเก็บไว้ในไฟล์ได้ กระบวนการในการอ่านสถานะของวัตถุจากไฟล์และเรียกคืนนั้นเรียกว่า deserialization
ความต้องการการทำให้เป็นอันดับคืออะไร?
ในสถาปัตยกรรมสมัยใหม่มีความจำเป็นต้องเก็บสถานะของวัตถุแล้วเรียกคืน ตัวอย่างเช่นใน Hibernate เพื่อเก็บวัตถุเราควรทำให้คลาสเป็น Serializable มันทำอะไรคือว่าเมื่อสถานะวัตถุถูกบันทึกในรูปแบบของไบต์ก็สามารถถ่ายโอนไปยังระบบอื่นซึ่งสามารถอ่านได้จากรัฐและดึงชั้นเรียน สถานะวัตถุสามารถมาจากฐานข้อมูลหรือ jvm ที่แตกต่างกันหรือจากองค์ประกอบที่แยกต่างหาก ด้วยความช่วยเหลือของการทำให้เป็นอันดับเราสามารถดึงสถานะของวัตถุ
ตัวอย่างรหัสและคำอธิบาย:
อันดับแรกให้ดูที่รายการระดับ:
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;
}
}
ในโค้ดข้างต้นจะเห็นได้ว่ารายการการดำเนินการระดับSerializable
นี่คืออินเทอร์เฟซที่เปิดใช้งานคลาสที่สามารถทำให้เป็นอนุกรมได้
ตอนนี้เราสามารถเห็นตัวแปรที่เรียกว่าserialVersionUIDนั้นถูกเตรียมใช้งานเป็นตัวแปร Long หมายเลขนี้คำนวณโดยคอมไพเลอร์ตามสถานะของคลาสและแอตทริบิวต์คลาส นี่คือหมายเลขที่จะช่วยให้ jvm ระบุสถานะของวัตถุเมื่ออ่านสถานะของวัตถุจากไฟล์
เพื่อให้เราสามารถดูเอกสารทางการของ Oracle:
ความสัมพันธ์รันไทม์ของการทำให้เป็นอนุกรมเชื่อมโยงกับหมายเลขรุ่นของคลาสที่เรียกว่า serialVersionUID ซึ่งใช้ในระหว่างการดีซีเรียลไลเซชันเพื่อตรวจสอบว่าผู้ส่งและผู้รับของวัตถุที่เป็นอนุกรมนั้นได้โหลดคลาสสำหรับวัตถุนั้นที่เข้ากันได้ หากผู้รับโหลดคลาสสำหรับวัตถุที่มี serialVersionUID ที่แตกต่างจากคลาสของผู้ส่งที่เกี่ยวข้องการดีซีเรียลไลซ์เซชั่นจะส่งผลให้เกิด InvalidClassException คลาสที่สามารถทำให้เป็นอนุกรมสามารถประกาศ serialVersionUID ของตัวเองได้อย่างชัดเจนโดยการประกาศฟิลด์ชื่อ "serialVersionUID" ที่ต้องเป็นแบบสแตติกสุดท้ายและแบบยาว: ANY-ACCESS-MODIFIER แบบคงที่แบบยาวสุดท้าย serialVersionUID = 42L; ถ้าคลาสที่สามารถทำให้เป็นอนุกรมไม่ได้ประกาศ serialVersionUID อย่างชัดเจน จากนั้นรันไทม์ของการทำให้เป็นอนุกรมจะคำนวณค่าเริ่มต้นของ serialVersionUID สำหรับคลาสนั้นตามแง่มุมต่าง ๆ ของคลาสดังที่อธิบายไว้ใน Java (TM) Object Serialization Specification อย่างไรก็ตามขอแนะนำอย่างยิ่งให้คลาสที่ทำให้เป็นอนุกรมทั้งหมดประกาศค่า serialVersionUID อย่างชัดเจนเนื่องจากการคำนวณ serialVersionUID เริ่มต้นนั้นมีความไวสูงต่อรายละเอียดของคลาสที่อาจแตกต่างกันไปขึ้นอยู่กับการใช้งานคอมไพเลอร์และอาจส่งผลให้ InvalidClassExceptions ดังนั้นเพื่อรับประกันค่า serialVersionUID ที่สอดคล้องกันระหว่างการประยุกต์ใช้คอมไพเลอร์ Java ที่แตกต่างกันคลาสที่ทำให้เป็นอนุกรมต้องประกาศค่า serialVersionUID ที่ชัดเจน ขอแนะนำอย่างชัดเจนว่าการประกาศ serialVersionUID อย่างชัดเจนใช้ตัวแก้ไขส่วนตัวหากเป็นไปได้
หากคุณสังเกตเห็นว่ามีคำหลักอื่นที่เราได้ใช้ซึ่งเป็นคำชั่วคราวชั่วคราว
หากเขตข้อมูลไม่ได้ต่อเนื่องได้จะต้องมีการทำเครื่องหมายชั่วคราว ที่นี่เราทำเครื่องหมายรายการราคาต้นทุนว่า transient และไม่ต้องการให้เขียนเป็นไฟล์
ตอนนี้เรามาดูวิธีการเขียนสถานะของวัตถุในไฟล์แล้วอ่านจากที่นั่น
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 เป็นโมฆะเนื่องจากไม่ได้เขียน
เราได้พูดถึงพื้นฐานของ Java Serialization แล้วในส่วนที่ฉันของบทความนี้
ตอนนี้เรามาพูดคุยกันอย่างลึกซึ้งและวิธีการทำงาน
ก่อนอื่นเรามาเริ่มด้วย serialversionuid ก่อน
The serialVersionUIDถูกนำมาใช้เป็นตัวควบคุมรุ่นในชั้นเรียน Serializable
หากคุณไม่ได้ประกาศ serialVersionUID อย่างชัดเจน JVM จะทำเพื่อคุณโดยอัตโนมัติโดยยึดตามคุณสมบัติต่าง ๆ ของคลาส Serializable
อัลกอริทึมของ Java ในการคำนวณ serialversionuid (อ่านรายละเอียดเพิ่มเติมที่นี่)
- ชื่อคลาส
- ตัวดัดแปลงคลาสที่เขียนเป็นจำนวนเต็ม 32 บิต
- ชื่อของแต่ละอินเตอร์เฟสเรียงตามชื่อ
- สำหรับแต่ละฟิลด์ของคลาสที่เรียงลำดับตามชื่อฟิลด์ (ยกเว้นฟิลด์สแตติกส่วนตัวและส่วนตัวชั่วคราว: ชื่อของฟิลด์ตัวดัดแปลงของฟิลด์ที่เขียนเป็นจำนวนเต็ม 32 บิตตัวบ่งชี้ของฟิลด์
- ถ้ามี initializer คลาสอยู่ให้เขียนดังต่อไปนี้: ชื่อของเมธอด,
- ตัวดัดแปลงของเมธอด java.lang.reflect.Modifier.STATIC ซึ่งเขียนเป็นจำนวนเต็ม 32 บิต
- ตัวบ่งชี้ของวิธีการ () V
- สำหรับตัวสร้างที่ไม่ใช่แบบส่วนตัวแต่ละรายการเรียงตามชื่อเมธอดและลายเซ็นต์: ชื่อของวิธีการ, ตัวดัดแปลงของวิธีการเขียนเป็นจำนวนเต็ม 32 บิต ตัวบ่งชี้ของวิธีการ
- สำหรับแต่ละวิธีที่ไม่เป็นส่วนตัวเรียงตามชื่อวิธีการและลายเซ็น: ชื่อของวิธีการ ตัวดัดแปลงของวิธีการเขียนเป็นจำนวนเต็ม 32 บิต ตัวบ่งชี้ของวิธีการ
- อัลกอริทึม SHA-1 ถูกเรียกใช้งานบนกระแสข้อมูลไบต์ที่สร้างโดย DataOutputStream และสร้างค่า 32- บิตห้าค่า sha [0..4] ค่าแฮชจะถูกรวบรวมจากค่า 32- บิตแรกและที่สองของการแยกย่อยข้อความ SHA-1 หากผลลัพธ์ของการแยกย่อยข้อความคำ 32- บิตห้า H0 H1 H2 H3 H4 อยู่ในอาร์เรย์ของห้าค่า int ที่ชื่อ sha ค่าแฮชจะถูกคำนวณดังนี้:
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;
อัลกอริทึมการทำให้เป็นอันดับของ Java
อัลกอริทึมในการทำให้เป็นอันดับวัตถุมีคำอธิบายดังต่อไปนี้:
1. มันเขียนข้อมูลเมตาของคลาสที่เกี่ยวข้องกับอินสแตนซ์
2. เขียนซ้ำจากคำอธิบายของ superclass จนกว่าจะพบjava.lang.Object
3. เมื่อเสร็จสิ้นการเขียนข้อมูลเมตาดาต้าจากนั้นเริ่มต้นด้วยข้อมูลจริงที่เชื่อมโยงกับอินสแตนซ์ แต่ครั้งนี้มันเริ่มต้นจากซุปเปอร์คลาสสูงสุด
4. มันจะเขียนข้อมูลที่เกี่ยวข้องกับอินสแตนซ์ซ้ำโดยเริ่มจากซูเปอร์คลาสอย่างน้อยไปยังคลาสที่ได้รับมามากที่สุด
สิ่งที่ควรทราบ:
ฟิลด์คงที่ในคลาสไม่สามารถต่อเนื่องกันได้
public class A implements Serializable{
String s;
static String staticString = "I won't be serializable";
}
ถ้า serialversionuid แตกต่างกันในคลาสอ่านมันจะโยนInvalidClassException
ข้อยกเว้น
หากคลาสดำเนินการทำให้เป็นอนุกรมแล้วคลาสย่อยทั้งหมดจะถูกทำให้เป็นอนุกรมได้
public class A implements Serializable {....};
public class B extends A{...} //also Serializable
ถ้าคลาสมีการอ้างอิงของคลาสอื่นการอ้างอิงทั้งหมดต้องเป็น Serializable มิฉะนั้นกระบวนการทำให้เป็นอนุกรมจะไม่ถูกดำเนินการ ในกรณีเช่นนี้NotSerializableExceptionจะถูกส่งไปที่รันไทม์
เช่น:
public class B{
String s,
A a; // class A needs to be serializable i.e. it must implement Serializable
}
serialVersionUID
จะแตกต่างกันก็จะโยนไม่InvalidClassException
ClassCastException
ไม่จำเป็นที่จะต้องเสียพื้นที่ทั้งหมดในserialVersionUID
การคำนวณ เอกสารที่ยกมามีความยาวมากเกินไป แต่ไม่ได้เชื่อมโยงหรืออ้างถึงอย่างถูกต้อง ปุยมากเกินไปที่นี่และมีข้อผิดพลาดมากเกินไป
การทำให้เป็นอันดับเป็นกระบวนการของการแปลงสถานะของวัตถุเป็นบิตเพื่อให้สามารถเก็บไว้ในฮาร์ดไดรฟ์ เมื่อคุณทำการดีซีเรียลไลซ์วัตถุเดียวกันวัตถุนั้นจะคงสถานะไว้ในภายหลัง มันช่วยให้คุณสร้างวัตถุใหม่โดยไม่ต้องบันทึกคุณสมบัติของวัตถุด้วยมือ
Serialization
เป็นกลไกในการแปลงกราฟของวัตถุ Java เป็นอาร์เรย์ของไบต์สำหรับการจัดเก็บ ( to disk file
) หรือการส่ง ( across a network
) จากนั้นใช้deserializationเราสามารถเรียกคืนกราฟของวัตถุ กราฟของวัตถุได้รับการกู้คืนอย่างถูกต้องโดยใช้กลไกการแบ่งปันอ้างอิง แต่ก่อนที่จะเก็บตรวจสอบว่า serialVersionUID จากอินพุตไฟล์ / เครือข่ายและ. class ไฟล์ serialVersionUID เหมือนกัน java.io.InvalidClassException
ถ้าไม่ได้โยน
คลาสที่กำหนดเวอร์ชันแต่ละคลาสจะต้องระบุเวอร์ชันคลาสดั้งเดิมที่สามารถเขียนสตรีมและสามารถอ่านได้ ตัวอย่างเช่นคลาสที่มีเวอร์ชันต้องประกาศ:
ไวยากรณ์ของ serialVersionUID
// ANY-ACCESS-MODIFIER static final long serialVersionUID = (64-bit has)L; private static final long serialVersionUID = 3487495895819393L;
serialVersionUIDเป็นสิ่งจำเป็นต่อกระบวนการทำให้เป็นอนุกรม แต่มันเป็นทางเลือกสำหรับนักพัฒนาเพื่อเพิ่มลงในซอร์สไฟล์ java หากไม่รวม serialVersionUID รันไทม์ของการทำให้เป็นอนุกรมจะสร้าง serialVersionUID และเชื่อมโยงกับคลาส วัตถุที่ทำให้เป็นอนุกรมจะมี serialVersionUID นี้พร้อมกับข้อมูลอื่น ๆ
หมายเหตุ - ขอแนะนำอย่างยิ่งให้คลาสที่สามารถทำให้เป็นอนุกรมทั้งหมดประกาศ serialVersionUID อย่างชัดเจนsince the default serialVersionUID computation is highly sensitive to class details that may vary depending on compiler implementations
และอาจส่งผลให้เกิดข้อขัดแย้ง serialVersionUID ที่ไม่คาดคิดในระหว่างการดีซีเรียลไลซ์เซชั่น
การตรวจสอบคลาสที่ต่อเนื่องกันได้
วัตถุ Java จะต่อเนื่องได้เท่านั้น ถ้าชั้นหรือใด ๆ ของ superclasses การดำเนินการของทั้งjava.io.Serializableอินเตอร์เฟซหรือ subinterface ของjava.io.Externalizable
คลาสต้องใช้อินเตอร์เฟส java.io.Serializableเพื่อทำให้วัตถุเป็นอนุกรมสำเร็จ Serializable เป็นอินเทอร์เฟซของตัวทำเครื่องหมายและใช้เพื่อแจ้งให้คอมไพเลอร์ทราบว่าการใช้คลาสนั้นจะต้องมีการเพิ่มลักษณะการทำงานแบบอนุกรมได้ ที่นี่ Java Virtual Machine (JVM) มีหน้าที่รับผิดชอบในการทำให้เป็นอนุกรมโดยอัตโนมัติ
คำหลักชั่วคราว:
java.io.Serializable interface
ในขณะที่ทำให้เป็นอันดับวัตถุถ้าเราไม่ต้องการให้สมาชิกข้อมูลบางส่วนของวัตถุเป็นอนุกรมเราสามารถใช้ตัวแก้ไขชั่วคราว คำหลักชั่วคราวจะป้องกันไม่ให้สมาชิกข้อมูลนั้นถูกทำให้เป็นอนุกรม
- เขตข้อมูลที่ประกาศเป็นชั่วคราวหรือคงที่จะถูกละเว้นโดยกระบวนการทำให้เป็นอันดับ
+--------------+--------+-------------------------------------+ | 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.
}
การใช้อินเทอร์เฟซ Externalizable ช่วยให้วัตถุสามารถควบคุมเนื้อหาและรูปแบบของแบบฟอร์มต่อเนื่องของวัตถุได้อย่างสมบูรณ์ เมธอดของอินเตอร์เฟส Externalizable, writeExternal และ readExternal ถูกเรียกใช้เพื่อบันทึกและกู้คืนสถานะอ็อบเจ็กต์ เมื่อใช้งานโดยคลาสพวกเขาสามารถเขียนและอ่านสถานะของตนเองโดยใช้วิธีการทั้งหมดของ ObjectOutput และ ObjectInput มันเป็นความรับผิดชอบของวัตถุที่จะจัดการกับเวอร์ชันใด ๆ ที่เกิดขึ้น
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
}
}
เฉพาะอ็อบเจ็กต์ที่สนับสนุนอินเตอร์เฟส java.io.Serializable หรือ java.io.Externalizable เท่านั้นที่สามารถwritten to
/read from
สตรีม คลาสของแต่ละวัตถุที่สามารถทำให้เป็นอนุกรมได้ถูกเข้ารหัสรวมถึงชื่อคลาสและลายเซ็นของคลาสค่าของเขตข้อมูลและอาร์เรย์ของวัตถุและการปิดวัตถุอื่น ๆ ที่อ้างอิงจากวัตถุเริ่มต้น
ตัวอย่างที่ทำให้ต่อเนื่องสำหรับไฟล์
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();
}
}
}
ตัวอย่างที่ทำให้เป็นอนุกรมผ่านเครือข่าย
การกระจายสถานะของวัตถุในพื้นที่ที่อยู่ที่แตกต่างกันไม่ว่าจะในกระบวนการต่าง ๆ บนคอมพิวเตอร์เครื่องเดียวกันหรือแม้กระทั่งในคอมพิวเตอร์หลายเครื่องที่เชื่อมต่อผ่านเครือข่าย แต่ทำงานร่วมกันโดยการแบ่งปันข้อมูลและวิธีการเรียกใช้
/**
* 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();
}
}
@ดู
JVM to JVM
การทำให้เป็นอันดับเป็นกระบวนการของการบันทึกวัตถุในสื่อบันทึก (เช่นไฟล์หรือบัฟเฟอร์หน่วยความจำ) หรือส่งผ่านการเชื่อมต่อเครือข่ายในรูปแบบไบนารี อ็อบเจ็กต์ที่ทำเป็นอนุกรมนั้นเป็นอิสระจาก JVM และสามารถถูกทำให้เป็นอนุกรมอีกครั้งโดย JVM ใด ๆ ในกรณีนี้สถานะวัตถุ java "ในหน่วยความจำ" จะถูกแปลงเป็นสตรีมไบต์ ผู้ใช้ไม่สามารถเข้าใจไฟล์ประเภทนี้ได้ เป็นวัตถุชนิดพิเศษที่ถูกนำมาใช้ซ้ำโดย JVM (Java Virtual Machine) กระบวนการในการทำให้เป็นอันดับวัตถุนี้เรียกว่าการยุบหรือการเรียงลำดับวัตถุ
วัตถุที่จะต่อเนื่องจะต้องใช้java.io.Serializable
Interface กลไกการทำให้เป็นอนุกรมเริ่มต้นสำหรับวัตถุเขียนคลาสของวัตถุ, ลายเซ็นคลาสและค่าของเขตข้อมูลที่ไม่ใช่แบบชั่วคราวและไม่คงที่ทั้งหมด
class ObjectOutputStream extends java.io.OutputStream implements ObjectOutput,
ObjectOutput
interface ขยายDataOutput
อินเตอร์เฟสและเพิ่มวิธีสำหรับซีเรียลไลซ์เซชันของวัตถุและการเขียนไบต์ไปยังไฟล์ ส่วนต่อObjectOutputStream
ขยายjava.io.OutputStream
และใช้งานObjectOutput
อินเตอร์เฟส มันซีเรียลไลซ์วัตถุอาร์เรย์และค่าอื่น ๆ กับสตรีม ดังนั้นตัวสร้างของ ObjectOutputStream
ถูกเขียนเป็น:
ObjectOutput ObjOut = new ObjectOutputStream(new FileOutputStream(f));
โค้ดด้านบนถูกใช้เพื่อสร้างอินสแตนซ์ของObjectOutput
คลาสด้วยตัวObjectOutputStream( )
สร้างซึ่งใช้อินสแตนซ์ของFileOuputStream
พารามิเตอร์
ObjectOutput
อินเตอร์เฟซที่ใช้งานโดยการดำเนินการObjectOutputStream
ระดับ ObjectOutputStream
ถูกสร้างขึ้นมาเพื่อเป็นอันดับวัตถุ
การดีซีเรียลไลซ์วัตถุใน java
การดำเนินการตรงข้ามของการทำให้เป็นอนุกรมเรียกว่าดีซีเรียลไลเซชั่นคือการดึงข้อมูลจากชุดของไบต์เป็นที่รู้จักกันในชื่อดีซีเรียลไลเซชั่น
ObjectInputStream
ขยายjava.io.InputStream
และใช้ObjectInput
อินเตอร์เฟส มัน deserializes วัตถุอาร์เรย์และค่าอื่น ๆ จากการป้อนข้อมูล ดังนั้นตัวสร้างของ ObjectInputStream
ถูกเขียนเป็น:
ObjectInputStream obj = new ObjectInputStream(new FileInputStream(f));
โค้ดด้านบนของโปรแกรมสร้างอินสแตนซ์ของObjectInputStream
คลาสเพื่อยกเลิกการซีเรียลObjectInputStream
ไลซ์ไฟล์ที่ถูกทำให้เป็นอนุกรมโดยคลาส รหัสข้างต้นสร้างอินสแตนซ์โดยใช้อินสแตนซ์ของFileInputStream
คลาสที่เก็บวัตถุไฟล์ที่ระบุซึ่งจะต้องมีการ deserialized เพราะคอนObjectInputStream()
สตรัคต้องการกระแสข้อมูล
การทำให้เป็นอันดับเป็นกระบวนการของการเปลี่ยนวัตถุ Java เป็นอาร์เรย์ไบต์แล้วกลับมาเป็นวัตถุอีกครั้งด้วยสถานะที่สงวนไว้ มีประโยชน์สำหรับสิ่งต่าง ๆ เช่นการส่งวัตถุผ่านเครือข่ายหรือแคชสิ่งของลงดิสก์
อ่านข้อมูลเพิ่มเติมจากบทความสั้น ๆ นี้ซึ่งจะอธิบายการเขียนโปรแกรมเป็นส่วนหนึ่งของกระบวนการที่ค่อนข้างดีและจากนั้นย้ายไปยังที่จะJavadoc Serializable คุณอาจสนใจอ่านคำถามที่เกี่ยวข้องนี้
ส่งคืนไฟล์เป็นวัตถุ: http://www.tutorialspoint.com/java/java_serialization.htm
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);
}
}
| * | การทำให้คลาสเป็นอนุกรม: การแปลงวัตถุเป็นไบต์และไบต์กลับไปเป็นวัตถุ (Deserialization)
class NamCls implements Serializable
{
int NumVar;
String NamVar;
}
| => Object-Serialization เป็นกระบวนการของการแปลงสถานะของวัตถุเป็นจำนวนเต็มไบต์
| => Object-Deserialization เป็นกระบวนการรับสถานะของวัตถุและเก็บไว้ในวัตถุ (java.lang.Object)
| => วัตถุ Java นั้นสามารถทำให้เป็นอนุกรมได้หากคลาสหรือซูเปอร์คลาสใด ๆ
| => ฟิลด์คงที่ในคลาสไม่สามารถต่อเนื่องกันได้
class NamCls implements Serializable
{
int NumVar;
static String NamVar = "I won't be serializable";;
}
| => หากคุณไม่ต้องการทำให้เป็นอนุกรมของคำสำคัญการใช้คลาสชั่วคราว
class NamCls implements Serializable
{
int NumVar;
transient String NamVar;
}
| => หากคลาสดำเนินการทำให้เป็นอนุกรมแล้วคลาสย่อยทั้งหมดของคลาสนั้นจะเป็นแบบอนุกรม
| => ถ้าคลาสมีการอ้างอิงของคลาสอื่นการอ้างอิงทั้งหมดต้องเป็นแบบอนุกรมได้มิฉะนั้นกระบวนการทำให้เป็นอนุกรมจะไม่ถูกดำเนินการ ในกรณีเช่นนี้
NotSerializableException จะถูกส่งไปที่รันไทม์
ฉันจะเสนอการเปรียบเทียบเพื่อช่วยในการทำให้วัตถุประสงค์เชิงแนวคิด / การปฏิบัติจริงของวัตถุเป็นอนุกรม / การดีซีเรียลไลซ์เซชันเป็นจริง
ฉันนึกภาพวัตถุเป็นอันดับ / deserializationในบริบทของความพยายามที่จะย้ายวัตถุผ่านพายุท่อระบายน้ำ วัตถุนั้นถูก "ย่อยสลาย" หรือต่อเนื่องเป็นรุ่นแยกส่วนของตัวเอง - ในกรณีนี้คือชุดของไบต์ - เพื่อให้ได้รับการส่งผ่านทางสื่ออย่างมีประสิทธิภาพ ในแง่การคำนวณเราสามารถดูเส้นทางที่เดินทางผ่านไบต์ผ่านช่องระบายพายุนั้นคล้ายกับจำนวนไบต์เดินทางผ่านเครือข่าย เรากำลังส่งผ่านวัตถุของเราเพื่อให้สอดคล้องกับโหมดการขนส่งหรือรูปแบบที่ต้องการมากขึ้น โดยทั่วไปแล้ววัตถุที่ต่อเนื่องกันจะถูกเก็บไว้ในไฟล์ไบนารีซึ่งอาจถูกอ่านจากเขียนหรือทั้งสองอย่างในภายหลัง
บางทีเมื่อวัตถุของเราสามารถลื่นไหลผ่านท่อระบายน้ำเป็นชุดย่อยของไบต์เราอาจต้องการที่จะเก็บการเป็นตัวแทนของวัตถุที่เป็นข้อมูลไบนารีภายในฐานข้อมูลหรือฮาร์ดดิสก์ไดรฟ์ ประเด็นหลักที่ว่าคือการทำให้เป็นอนุกรม / ดีซีเรียลไลเซชั่นเรามีตัวเลือกให้วัตถุของเราอยู่ในรูปแบบไบนารีหลังจากถูกทำให้เป็นอนุกรมหรือ "ดึง" รูปแบบดั้งเดิมของวัตถุโดยทำการดีซีเรียลไลเซชัน