เมื่อเร็ว ๆ นี้ฉันได้รวบรวมความรู้พื้นฐานของ Java และข้อมูลเกี่ยวกับการทำให้เป็นอนุกรม Java และ Deserialization ได้รับการคัดออกอย่างละเอียด ฉันจะจดบันทึกที่นี่โดยหวังว่ามันจะช่วยเพื่อนที่อ่านบทความนี้ด้วย
1. แนวคิดของการทำให้เป็นอนุกรมและ deserialization
กระบวนการแปลงวัตถุเป็นลำดับของไบต์เรียกว่าการทำให้เป็นอนุกรมของวัตถุ
กระบวนการกู้คืนลำดับของไบต์ลงในวัตถุเรียกว่า deserialization ของวัตถุ
มีการใช้งานหลักสองประการสำหรับการทำให้เป็นอนุกรมของวัตถุ:
1) บันทึกลำดับไบต์ของวัตถุอย่างถาวรบนฮาร์ดดิสก์โดยปกติจะอยู่ในไฟล์;
2) โอนลำดับไบต์ของวัตถุบนเครือข่าย
ในหลายแอปพลิเคชันวัตถุบางอย่างจำเป็นต้องได้รับการจัดลำดับเพื่อให้พวกเขาออกจากพื้นที่หน่วยความจำและไปยังฮาร์ดไดรฟ์ทางกายภาพสำหรับการจัดเก็บระยะยาว ตัวอย่างเช่นหนึ่งที่พบบ่อยที่สุดคือวัตถุเซสชันในเว็บเซิร์ฟเวอร์ เมื่อผู้ใช้ 100,000 คนเข้าถึงพร้อมกันวัตถุเซสชัน 100,000 รายการอาจปรากฏขึ้นและหน่วยความจำอาจไม่สามารถแบกรับได้ ดังนั้นเว็บคอนเทนเนอร์จะทำให้การตรวจพบฮาร์ดดิสก์บางส่วนเป็นอนุกรมก่อนและรอจนกว่าจะใช้แล้วคืนค่าวัตถุที่บันทึกไว้ในฮาร์ดดิสก์ไปยังหน่วยความจำ
เมื่อกระบวนการสองกระบวนการกำลังสื่อสารจากระยะไกลพวกเขาสามารถส่งข้อมูลประเภทต่าง ๆ ไปให้กัน ไม่ว่าข้อมูลประเภทใดจะถูกส่งบนเครือข่ายในรูปแบบของลำดับไบนารี ผู้ส่งจำเป็นต้องแปลงวัตถุ Java นี้เป็นลำดับของไบต์เพื่อที่จะส่งบนเครือข่าย ผู้รับจะต้องกู้คืนไบต์ให้เป็นวัตถุ Java
2. Serialization API ในไลบรารีคลาส JDK
java.io.ObjectOutputStream แสดงถึงกระแสเอาต์พุตของวัตถุ เมธอด WriteObject (Object OBJ) สามารถทำให้เป็นอนุกรมวัตถุ OBJ ที่ระบุโดยพารามิเตอร์และเขียนลำดับไบต์ที่ได้รับไปยังสตรีมเอาต์พุตเป้าหมาย
java.io.ObjectInputStream แสดงถึงสตรีมอินพุตวัตถุ วิธีการ readobject () อ่านลำดับไบต์จากสตรีมอินพุตต้นฉบับ deserializes พวกเขาลงในวัตถุและส่งคืนพวกเขา
เฉพาะวัตถุของคลาสที่ใช้อินเทอร์เฟซแบบอนุกรมและภายนอกที่สามารถปรับเปลี่ยนได้เท่านั้น อินเทอร์เฟซภายนอกที่สืบทอดมาจากอินเตอร์เฟส serializable คลาสที่ใช้อินเทอร์เฟซภายนอกที่สามารถควบคุมพฤติกรรมการทำให้เป็นอนุกรมได้อย่างสมบูรณ์ในขณะที่คลาสที่ใช้งานอินเตอร์เฟสแบบซีเรียลที่สามารถใช้งานได้เท่านั้นที่สามารถใช้วิธีการทำให้เป็นอนุกรมเริ่มต้นได้
การทำให้เป็นอนุกรมวัตถุรวมถึงขั้นตอนต่อไปนี้:
1) สร้างสตรีมเอาต์พุต Object ซึ่งสามารถห่อสตรีมเอาท์พุทเป้าหมายอีกประเภทหนึ่งเช่นสตรีมเอาต์พุตไฟล์
2) เขียนวัตถุผ่านวิธีการเขียน () ของสตรีมเอาต์พุตของวัตถุ
ขั้นตอนสำหรับการ deserializing วัตถุมีดังนี้:
1) สร้างสตรีมอินพุตวัตถุที่สามารถห่อสตรีมอินพุตต้นทางประเภทต่าง ๆ เช่นสตรีมอินพุตไฟล์
2) อ่านวัตถุผ่านวิธี readObject () ของสตรีมอินพุตวัตถุ
การทำให้เป็นอนุกรมของวัตถุและตัวอย่างที่ดี:
กำหนดคลาสบุคคลเพื่อใช้อินเตอร์เฟส serializable
1 นำเข้า java.io.serializable; 2 3 /** 4 * <p> classname: Person <p> 5 * <p> คำอธิบาย: การทดสอบวัตถุที่เป็นอนุกรมและ deserialization <p> 6 * @author xudp 7 * @version 1.0 V 8 * @createtime 2014-6-9 02:33:25 PM 9 * /10 Public Class Person SerialVersionUID = -5809782578272943999L; 16 INT INT อายุ 17 ชื่อสตริงส่วนตัว; 18 สตริงส่วนตัวเพศ; 19 20 INT INT GETAGE () {21 RETURN AGE; 22} 23 24 Public String getName () {25 ชื่อคืน 2 27} 27 อายุ; 34} 35 36 โมฆะสาธารณะ setName (ชื่อสตริง) {37 this.name = name; 38} 39 40 โมฆะสาธารณะ setsex (String sex) {41 this.sex = sex; 42} 43}ทำให้เป็นอนุกรมและ deserialize วัตถุระดับบุคคล
นำเข้า java.io.file; นำเข้า java.io.fileinputstream; นำเข้า java.io.filenotfoundException; นำเข้า java.io.fileoutputStream; นำเข้า java.io.ioException; นำเข้า java.io.ObjectInputStream; testobjserializeanddeserialize <p> * <p> คำอธิบาย: การทำให้เป็นอนุกรมและ deserialization ของวัตถุทดสอบ <p> * @author xudp * @version 1.0 V * @createtime 2014-6-9 03:17:25 PM */คลาสสาธารณะ serializeperson (); // serialize บุคคลวัตถุบุคคล perse p = deserializeperson (); // deserial perons object system.out.println (messageFormat.format ("ชื่อ = {0}, อายุ = {1}, เพศ = {2}", p.getName () } / ** * MethodName: SerializePerson * คำอธิบาย: Serialize Person Object * @author xudp * @throws filenotfoundexception * @throws ioexception * / โมฆะส่วนตัว serializeperson () โยน filenotfoundexception, ioexception person.setName ("GACL"); person.setage (25); person.setsex ("ชาย"); // ObjectOutputStream Object Output Stream จัดเก็บวัตถุบุคคลในไฟล์ person.txt บนดิสก์ E และดำเนินการต่ออนุกรมของวัตถุบุคคล ObjectOutputStream OO = ใหม่ ObjectOutputStream (ใหม่ fileOutputStream (ไฟล์ใหม่ ("e: /person.txt"))); oo.writeObject (บุคคล); System.out.println ("การทำให้เป็นอนุกรมของบุคคลนั้นประสบความสำเร็จ!"); oo.close (); }/** * MethodName: DeserializePerson * คำอธิบาย: Deserializeperson Object * @author Xudp * @return * @throws Exception * @throws ioexception */บุคคลคงที่ส่วนตัว deserializeperson () โยนข้อยกเว้น บุคคลบุคคล = (บุคคล) ois.readObject (); System.out.println ("บุคคลวัตถุ deserialization ประสบความสำเร็จ!"); คนกลับ; -ผลลัพธ์การเรียกใช้รหัสมีดังนี้:
หลังจากบุคคลที่เป็นอนุกรมประสบความสำเร็จไฟล์ person.txt ถูกสร้างขึ้นบนดิสก์ e ในขณะที่ผู้ deserializing ถูกใช้เพื่ออ่าน person.txt ของ e disk
3. บทบาทของ serialversionuid
seri al versi ui d: หมายถึงหมายเลขเวอร์ชันที่เป็นอนุกรม คลาสทั้งหมดที่ใช้อินเตอร์เฟส serializable มีตัวแปรคงที่แสดงถึงตัวระบุรุ่นอนุกรม
ส่วนตัวคงที่สุดท้าย
หาก SerialVersionUID ไม่ได้ถูกเพิ่มลงในชั้นเรียนคำเตือนต่อไปนี้จะปรากฏขึ้น
การคลิกด้วยเมาส์จะนำกล่องโต้ตอบที่สร้าง SerialVersionUID ดังแสดงในรูปด้านล่าง:
มีสองวิธีในการสร้าง serialversionuid:
serialversionuid ที่สร้างขึ้นในวิธีนี้คือ 1L ตัวอย่างเช่น:
ส่วนตัวคงที่สุดท้าย Long SerialVersionUid = 1L;
SerialVersionUID ที่สร้างขึ้นในวิธีนี้ถูกสร้างขึ้นตามชื่อคลาสชื่ออินเตอร์เฟสวิธีการและแอตทริบิวต์ ฯลฯ ตัวอย่างเช่น:
ส่วนตัวคงที่สุดท้าย Long SerialVersionUID = 460364234333777807741L;
หลังจากเพิ่มคำเตือนจะไม่ปรากฏดังที่แสดงด้านล่าง:
หลังจากพูดถึงมันแล้วการใช้ SerialVersionUID (หมายเลขเวอร์ชันที่เป็นอนุกรม) คืออะไร? มาใช้ตัวอย่างต่อไปนี้เพื่อแสดงบทบาทของ SerialVersionuid และดูรหัสต่อไปนี้:
1 นำเข้า Java.io.File; 2 นำเข้า Java.io.FileInputStream; 3 นำเข้า Java.io.filenotfoundException; 4 นำเข้า Java.io.FileOutputStream; 5 นำเข้า java.io.ioException; 6 นำเข้า Java.io.ObjectInputStream; 7 นำเข้า Java.io.ObjectOutputStream; 8 นำเข้า java.io.serializable; 9 10 Public Class TestserialVersionuid {11 12 โมฆะคงที่สาธารณะหลัก (String [] args) พ่นข้อยกเว้น {13 serializecustomer (); // serialize ลูกค้าวัตถุ 14 ลูกค้า = deserializecustomer (); // deserial ลูกค้าวัตถุ 15 ระบบ * @author xudp22 * @throws filenotfoundexception23 * @throws ioexception24 */25 โมฆะส่วนตัวคงที่ serializecustomer () โยน filenotfoundexception 26 ioexception {27 ลูกค้า = ลูกค้าใหม่ ("gacl", 25) FileOutputStream (30 ไฟล์ใหม่ ("E: /Customer.txt"))); 31 oo.writeObject (ลูกค้า); 32 System.out.println ("ลูกค้าวัตถุที่เป็นอนุกรมประสบความสำเร็จ!"); 33 oo.close (); 34} 35 36 /** 37 * xudp40 * @return41 * @throws exception42 * @throws ioexception43 */44 ลูกค้าคงที่ส่วนตัว deserializeCustomer () โยนข้อยกเว้น, iOexception {45 ObjectInputStream ois = new ObjectInputStream (ใหม่ FileInputStream (46 ไฟล์ใหม่ ( ois.readobject (); 48 System.out.println ("ลูกค้าวัตถุ deserialization ประสบความสำเร็จ! "); 49 ส่งคืนลูกค้า; 50} 51} 52 53 /** 54 * <p> คลาสชื่อ: ลูกค้า <p> 55 * <p> คำอธิบาย: ลูกค้าใช้อินเตอร์เฟส serializable และสามารถเป็น serialized <p> 56 * @author xudp57 * @version 1.0 V58 * @creatime {61 // ไม่มี SerialVersionUID62 ชื่อสตริงส่วนตัว; 63 Private Int อายุ; 64 65 ลูกค้าสาธารณะ (ชื่อสตริง, อายุ int) {66 this.name = name; 67 this.age = อายุ; 68} 69 70 / * 71 * @methodname toString72 * @description rewrite the tostring @return String75 * @See Java.lang.Object#toString () 76 */77 @Override78 Public String toString () {79 return "name =" + name + ", age =" + age; 80} 81}ผลการทำงาน:
ทั้งการทำให้เป็นอนุกรมและ deserialization ประสบความสำเร็จ
มาปรับเปลี่ยนคลาสลูกค้าและเพิ่มแอตทริบิวต์ทางเพศเพิ่มเติมดังนี้:
1 คลาสลูกค้าใช้ serializable {2 // ไม่มี serialVersionuID ถูกกำหนดไว้ในชื่อลูกค้าคลาส 3 ชื่อส่วนตัว 4 อายุ int ส่วนตัว; 5 6 // แอตทริบิวต์เพศใหม่ 7 เซ็กซ์สตริงส่วนตัว; 8 9 ลูกค้าสาธารณะ (ชื่อสตริงอายุ int) {10 this.name = ชื่อ; 11 this.age = อายุ; 12} 13 14 ลูกค้าสาธารณะ (ชื่อสตริงอายุ int, String sex) {15 this.name = ชื่อ; 16 this.age = อายุ; 17 this.sex = sex; 18} 19 20 / * 21 * @methodname Xudp24 * @return String25 * @See Java.lang.Object#toString () 26 */27 @override28 สตริงสาธารณะ toString () {29 return "name =" + name + ", อายุ =" + อายุ; 30} 31}}จากนั้นดำเนินการ Desequence และข้อมูลข้อยกเว้นต่อไปนี้จะถูกโยนลงไป:
1 ข้อยกเว้นในเธรด "Main" Java.io.invalidClassexception: ลูกค้า; 2 คลาสท้องถิ่นเข้ากันไม่ได้: 3 สตรีม classdesc serialversionuid = -88175599799432325, 4 คลาสท้องถิ่น serialversionuid = -5182532647273106745
ซึ่งหมายความว่าคลาสในสตรีมไฟล์และคลาสใน classpath นั่นคือคลาสที่แก้ไขแล้วไม่เข้ากัน พวกเขาอยู่ภายใต้การพิจารณากลไกความปลอดภัย โปรแกรมส่งข้อผิดพลาดและปฏิเสธที่จะโหลด แล้วถ้าเราจำเป็นต้องเพิ่มฟิลด์หรือวิธีการหลังจากการทำให้เป็นอนุกรม ฉันควรทำอย่างไร? นั่นคือการระบุ serialversionuid ด้วยตัวคุณเอง ในตัวอย่าง testserialversionuid หาก serialversionuid ของคลาสลูกค้าไม่ได้ระบุแล้วคอมไพเลอร์ Java จะดำเนินการอัลกอริทึมสรุปโดยอัตโนมัติสำหรับคลาสนี้คล้ายกับอัลกอริทึมลายนิ้วมือ ตราบใดที่ไฟล์มีพื้นที่อีกหนึ่งพื้นที่ UID ที่ได้จะแตกต่างกันอย่างสิ้นเชิงซึ่งสามารถรับประกันได้ว่าหมายเลขนี้ไม่ซ้ำกันในชั้นเรียนมากมาย ดังนั้นหลังจากเพิ่มฟิลด์เนื่องจากไม่ได้ระบุ serialVersionUID แล้วคอมไพเลอร์จะสร้าง UID สำหรับเราซึ่งแน่นอนว่าไม่เหมือนกับที่บันทึกไว้ในไฟล์มาก่อนดังนั้นจึงมีข้อผิดพลาดสองข้อที่มีหมายเลขรุ่นต่อเนื่องที่ไม่สอดคล้องกัน ดังนั้นตราบใดที่เราระบุ SerialVersionUid ตัวเองเราสามารถเพิ่มสนามหรือวิธีการหลังจากการทำให้เป็นอนุกรมโดยไม่ส่งผลกระทบต่อการฟื้นฟูในภายหลัง วัตถุที่ได้รับการฟื้นฟูยังสามารถใช้งานได้และยังมีวิธีการหรือคุณลักษณะเพิ่มเติมที่จะใช้
จากนั้นดำเนินการต่อเพื่อปรับเปลี่ยนคลาสลูกค้าและระบุ serialVersionUID ให้กับลูกค้า รหัสที่แก้ไขมีดังนี้:
ลูกค้าในชั้นเรียนใช้ serializable { / ** * serialVersionUID (หมายเลขเวอร์ชันอนุกรม) ที่กำหนดไว้ในคลาสลูกค้า * / ส่วนตัวคงที่สุดท้าย Long SerialVersionUID = -5182532647273106745L; ชื่อสตริงส่วนตัว; อายุ int ส่วนตัว; // คุณลักษณะทางเพศใหม่ // เซ็กส์สตริงส่วนตัว; ลูกค้าสาธารณะ (ชื่อสตริงอายุ int) {this.name = name; this.age = อายุ; } /*ลูกค้าสาธารณะ (ชื่อสตริงอายุ int, String sex) {this.name = name; this.age = อายุ; this.sex = เพศ; } *// * * * @methodname toString * @description เขียน toString () วิธีการของคลาสวัตถุ * @author xudp * @return String * @See Java.lang.Object#TOSTRING () */ @OverRide -ดำเนินการอีกครั้งการดำเนินการอนุกรมทำให้วัตถุลูกค้าเป็นอนุกรมไปยังที่เก็บไฟล์ txt customer.txt บนฮาร์ดดิสก์ท้องถิ่นจากนั้นแก้ไขคลาสลูกค้าและเพิ่มแอตทริบิวต์เพศ รหัสคลาสลูกค้าที่ได้รับการแก้ไขมีดังนี้:
ลูกค้าในชั้นเรียนใช้ serializable { / ** * serialVersionUID (หมายเลขเวอร์ชันอนุกรม) ที่กำหนดไว้ในคลาสลูกค้า * / ส่วนตัวคงที่สุดท้าย Long SerialVersionUID = -5182532647273106745L; ชื่อสตริงส่วนตัว; อายุ int ส่วนตัว; // คุณลักษณะทางเพศใหม่เซ็กซ์ส่วนตัว; ลูกค้าสาธารณะ (ชื่อสตริงอายุ int) {this.name = name; this.age = อายุ; } ลูกค้าสาธารณะ (ชื่อสตริงอายุ int, String sex) {this.name = name; this.age = อายุ; this.sex = เพศ; } / * * @methodname toString * @description เขียนใหม่ toString () เมธอดของคลาสวัตถุ * @author xudp * @return string * @see java.lang.object#toString () * / @Override สตริงสาธารณะ -ดำเนินการ desequence และความเท่าเทียมจะประสบความสำเร็จในเวลานี้ดังที่แสดงด้านล่าง:
4. ค่าของ serialversionuid
ค่าของ serialversionuid จะถูกสร้างขึ้นโดยอัตโนมัติโดยสภาพแวดล้อม Java Runtime ตามรายละเอียดภายในของคลาส หากซอร์สโค้ดของคลาสได้รับการแก้ไขและคอมไพล์ใหม่ค่าของ serialversionuid ของไฟล์คลาสที่สร้างขึ้นใหม่อาจเปลี่ยนแปลงได้เช่นกัน
ค่าเริ่มต้นของ serialversionuid ของคลาสขึ้นอยู่กับการใช้งานคอมไพเลอร์ Java สำหรับคลาสเดียวกันการรวบรวมด้วยคอมไพเลอร์ Java ที่แตกต่างกันอาจนำไปสู่ serialversionuids ที่แตกต่างกันและอาจเหมือนกัน เพื่อปรับปรุงความเป็นอิสระและความมั่นใจของ serialversionuid ขอแนะนำอย่างยิ่งในการกำหนด serialversionuid ที่แสดงในคลาส serializable โดยกำหนดค่าที่ชัดเจน
มีสองวัตถุประสงค์สำหรับการกำหนด serialversionuid อย่างชัดเจน:
1. ในบางกรณีคาดว่าคลาสที่แตกต่างกันของคลาสจะเข้ากันได้กับการทำให้เป็นอนุกรมดังนั้นจึงจำเป็นเพื่อให้แน่ใจว่ารุ่นที่แตกต่างกันของคลาสมี serialversionuid เดียวกัน
2. ในบางกรณีไม่คาดว่าจะเป็นรุ่นที่แตกต่างกันกับการทำให้เป็นอนุกรมดังนั้นจึงจำเป็นเพื่อให้แน่ใจว่าคลาสที่แตกต่างกันมี serialversionuids ที่แตกต่างกัน
ขอบคุณสำหรับการอ่านฉันหวังว่ามันจะช่วยคุณได้ ขอบคุณสำหรับการสนับสนุนเว็บไซต์นี้!