เหตุผลเฉพาะที่clone()
กำหนดไว้ว่าได้รับการคุ้มครองjava.lang.Object
คืออะไร?
เหตุผลเฉพาะที่clone()
กำหนดไว้ว่าได้รับการคุ้มครองjava.lang.Object
คืออะไร?
คำตอบ:
ความจริงที่ว่าโคลนได้รับการป้องกันนั้นเป็นเรื่องที่น่าสงสัยอย่างยิ่งเช่นเดียวกับความจริงที่ว่าclone
วิธีนี้ไม่ได้รับการประกาศในCloneable
อินเทอร์เฟซ
ทำให้วิธีนี้ไม่มีประโยชน์สำหรับการคัดลอกข้อมูลเพราะคุณไม่สามารถพูดว่า :
if(a instanceof Cloneable) {
copy = ((Cloneable) a).clone();
}
ฉันคิดว่าCloneable
ตอนนี้การออกแบบส่วนใหญ่ถือเป็นความผิดพลาด (อ้างอิงด้านล่าง) โดยปกติฉันต้องการที่จะสามารถใช้งานอินเทอร์เฟซได้Cloneable
แต่ไม่จำเป็นต้องสร้างอินเทอร์เฟซCloneable
(คล้ายกับการใช้งานSerializable
) สิ่งนี้ไม่สามารถทำได้หากไม่มีการไตร่ตรอง:
ISomething i = ...
if (i instanceof Cloneable) {
//DAMN! I Need to know about ISomethingImpl! Unless...
copy = (ISomething) i.getClass().getMethod("clone").invoke(i);
}
การอ้างอิงจากJava ที่มีประสิทธิภาพของ Josh Bloch :
"อินเทอร์เฟซ Cloneable มีไว้เพื่อใช้เป็นอินเทอร์เฟซแบบ mixin สำหรับอ็อบเจ็กต์เพื่อโฆษณาว่าอนุญาตให้มีการโคลนนิ่ง แต่น่าเสียดายที่ไม่สามารถตอบสนองวัตถุประสงค์นี้ได้ ... นี่เป็นการใช้อินเทอร์เฟซที่ผิดปกติอย่างมากและไม่มีการเลียนแบบ ... เพื่อให้การใช้งานอินเทอร์เฟซมีผลกับคลาสใดคลาสหนึ่งมันและคลาสซูเปอร์คลาสทั้งหมดจะต้องเป็นไปตามโปรโตคอลที่ค่อนข้างซับซ้อนไม่สามารถบังคับใช้ได้และส่วนใหญ่ไม่มีเอกสาร "
Serializable
- ขึ้นอยู่กับการนำไปใช้งานเพื่อตัดสินใจว่าจะใช้งานSerializable
หรือไม่ ผมได้รับการขยายนี้Cloneable
- มันไม่ได้เป็นสิ่งที่อินเตอร์เฟซที่ควรขยาย - Cloneable
แต่การดำเนินการของอินเตอร์เฟซที่มีอิสระที่จะเป็น ปัญหาคือถ้าคุณมีพารามิเตอร์ของประเภทอินเทอร์เฟซคุณจะถามว่ามันสามารถโคลนได้หรือไม่ แต่แล้วคุณไม่สามารถโคลนได้จริง!
อินเทอร์เฟซ Clonable เป็นเพียงเครื่องหมายบอกว่าคลาสสามารถรองรับการโคลนได้ เมธอดนี้ได้รับการป้องกันเนื่องจากคุณไม่ควรเรียกมันบนวัตถุคุณสามารถ (และควร) แทนที่เป็นสาธารณะ
ตั้งแต่อาทิตย์:
ในคลาส Object จะมีการประกาศวิธีการ clone () ที่ได้รับการป้องกัน หากสิ่งที่คุณทำคือใช้ Cloneable เฉพาะคลาสย่อยและสมาชิกของแพ็กเกจเดียวกันเท่านั้นที่จะสามารถเรียกใช้ clone () บนอ็อบเจ็กต์ได้ ในการเปิดใช้งานคลาสใด ๆ ในแพ็คเกจใด ๆ เพื่อเข้าถึงวิธีการ clone () คุณจะต้องลบล้างและประกาศเป็นสาธารณะดังที่ทำด้านล่าง (เมื่อคุณลบล้างวิธีการคุณสามารถทำให้เป็นส่วนตัวน้อยลง แต่ไม่เป็นส่วนตัวมากขึ้นที่นี่เมธอด clone () ที่มีการป้องกันใน Object จะถูกแทนที่เป็นวิธีสาธารณะ)
Set
clone
ได้รับการปกป้องเนื่องจากเป็นสิ่งที่ควรจะถูกแทนที่เพื่อให้เฉพาะกับคลาสปัจจุบัน แม้ว่าจะเป็นไปได้ที่จะสร้างclone
เมธอดสาธารณะที่จะโคลนอ็อบเจ็กต์ใด ๆ เลย แต่ก็ไม่ดีเท่ากับเมธอดที่เขียนขึ้นเฉพาะสำหรับคลาสที่ต้องการ
ไม่สามารถใช้เมธอด Clone กับวัตถุใด ๆ ได้โดยตรงซึ่งเป็นสาเหตุที่ทำให้คลาสย่อยถูกลบล้าง
แน่นอนว่าอาจเป็นสาธารณะและเพียงแค่โยนข้อยกเว้นที่เหมาะสมเมื่อไม่สามารถทำการโคลนนิ่งได้ แต่ฉันคิดว่านั่นจะทำให้เข้าใจผิด
วิธีการใช้งานโคลนในตอนนี้ทำให้คุณคิดถึงสาเหตุที่คุณต้องการใช้โคลนและวิธีที่คุณต้องการให้วัตถุของคุณถูกโคลน
มันได้รับการคุ้มครองเพราะเริ่มต้นใช้งานไม่สำเนาตื้น memberwise ของทุกสาขา (รวมทั้งเอกชน) หลีกเลี่ยงคอนสตรัค นี่ไม่ใช่สิ่งที่ออบเจ็กต์อาจได้รับการออกแบบมาเพื่อจัดการตั้งแต่แรก (เช่นอาจติดตามอินสแตนซ์ออบเจ็กต์ที่สร้างขึ้นในรายการที่แชร์หรือสิ่งที่คล้ายกัน)
ด้วยเหตุผลเดียวกันที่เริ่มต้นใช้งานจะโยนถ้าวัตถุที่มันเรียกว่าไม่ใช้clone()
Cloneable
เป็นการดำเนินการที่อาจไม่ปลอดภัยและมีผลกระทบในวงกว้างดังนั้นผู้เขียนชั้นเรียนจึงต้องเลือกเข้าร่วมอย่างชัดเจน
จาก javadoc ของ cloneable
* By convention, classes that implement this interface (cloneable) should override
* <tt>Object.clone</tt> (which is protected) with a public method.
* See {@link java.lang.Object#clone()} for details on overriding this
* method.
* Note that this interface does <i>not</i> contain the <tt>clone</tt> method.
* Therefore, it is not possible to clone an object merely by virtue of the
* fact that it implements this interface. Even if the clone method is invoked
* reflectively, there is no guarantee that it will succeed.
ดังนั้นคุณสามารถเรียกโคลนบนวัตถุทุกชิ้นได้ แต่จะให้เวลาส่วนใหญ่ไม่ใช่ผลลัพธ์ที่คุณต้องการหรือเป็นข้อยกเว้น แต่จะได้รับการสนับสนุนเฉพาะในกรณีที่คุณใช้โคลนได้
IMHO ง่ายเพียงเท่านี้:
#clone
จะต้องไม่ถูกเรียกใช้กับวัตถุที่ไม่สามารถโคลนได้ดังนั้นจึงไม่เปิดเผยต่อสาธารณะ#clone
จะต้องถูกเรียกโดยคลาสย่อย ob Object
ที่ใช้ Cloneable เพื่อให้ได้สำเนาตื้นของคลาสที่ถูกต้องขอบเขตที่เหมาะสมสำหรับเมธอดที่คลาสย่อยสามารถเรียกใช้ได้คืออะไร แต่คลาสอื่นไม่สามารถเรียกใช้ได้
มันprotected
.
ชั้นเรียนที่ใช้Cloneable
หลักสูตรจะทำให้วิธีนี้เป็นสาธารณะดังนั้นจึงสามารถเรียกจากชั้นเรียนอื่น ๆ ได้
วิธีการ Clone () มีการตรวจสอบ 'อินสแตนซ์ของ Cloneable หรือไม่' ภายในนี่คือวิธีที่ทีม Java อาจคิดว่าจะ จำกัด การใช้ clone () method ที่ไม่เหมาะสมวิธีการ clone () ได้รับการป้องกันเช่นเข้าถึงโดยคลาสย่อยเท่านั้น เนื่องจากออบเจ็กต์เป็นคลาสแม่ของคลาสย่อยทั้งหมดดังนั้น Clone () จึงสามารถใช้กับคลาสทั้งหมดได้หากเราไม่มีการตรวจสอบ 'อินสแตนซ์ของ Cloneable' ข้างต้น นี่คือเหตุผลที่ทีม Java อาจคิดที่จะ จำกัด การใช้ clone () ที่ไม่เหมาะสมโดยการตรวจสอบใน clone () method 'is it instance of Cloneable'
ดังนั้นคลาสใดก็ตามที่ใช้ cloneable สามารถใช้ clone () method ของ Object class ได้
นอกจากนี้เนื่องจากมีการป้องกันจึงมีให้เฉพาะคลาสย่อยที่ใช้อินเทอร์เฟซที่สามารถโคลนได้ หากเราต้องการทำให้เป็นสาธารณะวิธีนี้จะต้องถูกแทนที่โดยคลาสย่อยด้วยการนำไปใช้งานเอง
ใช่ปัญหาเดียวกับที่ฉันพบ แต่ฉันแก้ปัญหาด้วยการใช้โค้ดนี้
public class Side implements Cloneable {
public Side clone() {
Side side = null;
try {
side = (Side) super.clone();
} catch (CloneNotSupportedException e) {
System.err.println(e);
}
return side;
}
}
เช่นเดียวกับที่ก่อนหน้านี้มีคนกล่าวว่า
นอกจากนี้นักพัฒนาดวงอาทิตย์ยังเป็นเพียงมนุษย์เท่านั้นและพวกเขาทำผิดพลาดอย่างมากในการใช้วิธีการโคลนตามที่ได้รับการป้องกันซึ่งเป็นข้อผิดพลาดเดียวกันกับที่พวกเขาใช้วิธีโคลนที่ไม่ทำงานใน ArrayList! ดังนั้นโดยทั่วไปมีความเข้าใจผิดที่ลึกซึ้งยิ่งขึ้นของโปรแกรมเมอร์ Java ที่มีประสบการณ์เกี่ยวกับวิธีการโคลน
อย่างไรก็ตามเมื่อเร็ว ๆ นี้ฉันได้พบวิธีที่ง่ายและรวดเร็วในการคัดลอกวัตถุใด ๆ ที่มีเนื้อหาทั้งหมดไม่ว่าจะสร้างขึ้นอย่างไรและมีอะไรบ้างโปรดดูคำตอบของฉันที่นี่: ข้อบกพร่องในการใช้ Object.clone ()
อีกครั้งกรอบ Java JDK แสดงให้เห็นถึงความคิดที่ยอดเยี่ยม:
อินเทอร์เฟซ Cloneable ไม่มี "public T clone ();" วิธีการเนื่องจากทำหน้าที่คล้ายกับแอตทริบิวต์ (เช่นต่ออนุกรมได้) ซึ่งอนุญาตให้โคลนอินสแตนซ์ได้
การออกแบบนี้ไม่มีอะไรผิดปกติเนื่องจาก:
Object.clone () จะไม่ทำสิ่งที่คุณต้องการด้วยคลาสที่กำหนดเองของคุณ
หากคุณมี Myclass ใช้ Cloneable => คุณเขียนทับ clone () ด้วย "public MyClass clone ()"
หากคุณมี MyInterface ขยาย Cloneable และ MyClasses บางตัวใช้ MyInterface: เพียงกำหนด "โคลน MyInterface สาธารณะ ();" ในอินเทอร์เฟซและทุกวิธีที่ใช้วัตถุ MyInterface จะสามารถโคลนพวกมันได้ไม่ว่าจะเป็นคลาส MyClass ก็ตาม