1. แนวคิดการคัดลอกแบบตื้นและการคัดลอกลึก
⑴ Shallow Copy (การโคลนนิ่งตื้น)
ตัวแปรทั้งหมดของวัตถุที่คัดลอกมีค่าเดียวกับวัตถุดั้งเดิมในขณะที่การอ้างอิงทั้งหมดไปยังวัตถุอื่น ๆ ยังคงชี้ไปที่วัตถุดั้งเดิม กล่าวอีกนัยหนึ่งการคัดลอกตื้นเพียงแค่คัดลอกวัตถุที่ถูกพิจารณาไม่ใช่วัตถุที่อ้างอิง
⑵สำเนาลึก (การโคลนลึก)
ตัวแปรทั้งหมดของวัตถุที่คัดลอกมีค่าเดียวกับวัตถุดั้งเดิมยกเว้นตัวแปรเหล่านั้นที่อ้างถึงวัตถุอื่น ๆ ตัวแปรเหล่านั้นที่อ้างถึงวัตถุอื่น ๆ จะชี้ไปที่วัตถุใหม่ที่คัดลอกมาแทนที่จะเป็นวัตถุอ้างอิงต้นฉบับ กล่าวอีกนัยหนึ่งสำเนาลึกคัดลอกวัตถุทั้งหมดที่อ้างอิงโดยวัตถุที่จะคัดลอก
2. วิธีการโคลนของ Java ()
⑴วิธีการโคลนคัดลอกสำเนาของวัตถุและส่งคืนไปยังผู้โทร โดยทั่วไปวิธีการโคลน () เป็นไปตาม:
①สำหรับวัตถุใด ๆ x มี x.clone ()! = x // วัตถุที่โคลนไม่ใช่วัตถุเดียวกับวัตถุดั้งเดิม②สำหรับวัตถุใด ๆ x มี x.clone (). getClass () = = x . getClass () // วัตถุโคลนเหมือนกับประเภทของวัตถุต้นฉบับ③ถ้าวิธีการเท่ากับ () ของวัตถุ x ถูกกำหนดอย่างเหมาะสมแล้ว x.clone (). เท่ากับ (x) ควรเป็นจริง
⑵โคลนนิ่งของวัตถุใน Java
①เพื่อให้ได้สำเนาของวัตถุเราสามารถใช้วิธีการโคลน () ของคลาสวัตถุ
②เขียนทับวิธีการโคลน () ของคลาสฐานในคลาสที่ได้รับและประกาศว่าเป็นสาธารณะ
③ในวิธีการโคลน () ของคลาสที่ได้รับโทร super.clone ()
④ใช้อินเทอร์เฟซ cloneable ในคลาสที่ได้รับ
โปรดดูรหัสต่อไปนี้:
นักเรียนชั้นเรียนใช้ชื่อ cloneable {string name; นักเรียน) super.clone (); // clone () ในวัตถุรับรู้วัตถุที่คุณต้องการคัดลอก } catch (clonenotsupportedexception e) {system.out.println (e.toString ()); S2 = (นักเรียน) S1.Clone (); S2.name = "Lisi"; System.out.println ("name ="+s1.name+","+"age ="+s1.age); +s2.age);}} ภาพประกอบ:
①ทำไมเราต้องเรียก super.clone () เมื่อเขียนทับวิธีโคลน () ของวัตถุในคลาสที่ได้รับ? ในเวลาทำงาน Clone () ในวัตถุจะจดจำวัตถุที่คุณต้องการคัดลอกจากนั้นจัดสรรพื้นที่สำหรับวัตถุนี้และคัดลอกวัตถุคัดลอกเนื้อหาของวัตถุต้นฉบับทีละหนึ่งในพื้นที่เก็บข้อมูลของวัตถุใหม่
②วิธีการโคลน () ที่สืบทอดมาจากคลาส java.lang.Object เป็นสำเนาตื้น รหัสต่อไปนี้สามารถพิสูจน์ได้
อาจารย์ชั้นเรียน {ชื่อสตริง; อายุ int; นักเรียน (ชื่อสตริง, อายุ, ศาสตราจารย์ p) {this.name = name; . clone (); ) {ศาสตราจารย์ P = ศาสตราจารย์ใหม่ ("Wangwu", 50); "; s2.p.age = 30; system.out.println (" name = "+s1.p.name+", "+" age = "+s1.p.age); system.out.println (" ชื่อ = "+s2.p.name+", "+" อายุ = "+s2.p.age); // ผลการส่งออกของอาจารย์ของนักเรียน 1 และ 2 กลายเป็น lisi และอายุคือ 30 - ดังนั้นเราควรใช้การโคลนนิ่งลึก ๆ นั่นคือศาสตราจารย์ที่ปรับเปลี่ยน S2 จะไม่ส่งผลกระทบต่อศาสตราจารย์ที่ S1 รหัสได้รับการปรับปรุงดังนี้
การปรับปรุงเพื่อให้อาจารย์ของนักเรียน 1 ไม่เปลี่ยนแปลง (deep clone)
ศาสตราจารย์ใช้ชื่อ {สตริงอายุ; clone (); อายุ, ศาสตราจารย์ P) {this.name = ชื่อ; } catch (clonenotsupportedexception e) {system.out.println (e.toString ()); ] args) {ศาสตราจารย์ P = ศาสตราจารย์ใหม่ ("Wangwu", 50); "Lisi"; S2.p.age = 30; System.out.println ("name ="+s1.p.name+","+"age ="+s1.p.age); "+" age = "+s2.p.age);}} 3.利用串行化来做深复制(主要是为了避免重写比较复杂对象的深复制的clone()方法,也可以程序实现断点续传等等功能)
กระบวนการเขียนวัตถุลงในสตรีมเป็นกระบวนการทำให้เป็นอนุกรม แต่มันเรียกว่ากระบวนการ "แช่แข็ง" หรือ "การเลือก" ในวงกลมของโปรแกรมเมอร์ Java และการอ่านวัตถุจากสตรีมกระบวนการขนานที่เกิดขึ้นเรียกว่า กระบวนการ.
ควรชี้ให้เห็นว่าสิ่งที่เขียนในสตรีมเป็นสำเนาของวัตถุและวัตถุต้นฉบับยังคงอยู่ใน JVM ดังนั้นสิ่งที่ "ดองเป็นผักดอง" เป็นเพียงสำเนาของวัตถุ สดชื่น
การคัดลอกวัตถุอย่างลึกซึ้งในภาษา Java มักจะทำให้วัตถุใช้อินเทอร์เฟซแบบอนุกรมก่อนจากนั้นเขียนวัตถุ (จริง ๆ แล้วเพียงแค่สำเนาของวัตถุ) ลงในสตรีม (ดองเป็นผักดอง) จากนั้นอ่านจากสตรีม (ใส่ ผักดองกลับ) สามารถสร้างวัตถุขึ้นมาใหม่
ต่อไปนี้เป็นซอร์สโค้ดสำเนาลึก
วัตถุสาธารณะ DeepClone () {// เขียนวัตถุลงในสตรีม ByteArrayoutStream BO = ใหม่ ByteArrayOutputStream (); bo.tobytearray ()); หลักฐานของการทำเช่นนี้คือวัตถุและวัตถุที่อ้างอิงทั้งหมดภายในวัตถุนั้นสามารถทำให้เป็นอนุกรมได้ . ข้างนอก. รหัสตัวอย่างข้างต้นได้รับการปรับปรุงดังนี้
อาจารย์ประจำชั้นใช้ชื่อ {สตริงอายุ; อายุ; ครู T; // ค่าอ้างอิงของนักเรียน 1 และนักเรียน 2 เหมือนกัน นักเรียนเป็นโมฆะ (ชื่อสตริง, อายุ, ครู t) {this.name = name; ไปที่สตรีม ByteArrayOutStream BO = ใหม่ ByteArrayOutputStream (); ใหม่ ObjectInputStream (BI); 18, T); name = "+s1.t.name+", "+" age = "+s1.t.age);}}