定义:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
解释:我有一幅《清明上河图》的原画卷(原型实例),我通过复印机复印这幅原画卷得到了新的画卷(新的对象)。
// 画家
public class Painter{
// 姓名
private String name;
public String getName(){
return this.name;
}
public void setName(String name){
this.name = name;
}
}
/* 画卷:实现 Cloneable 接口.
(1)Cloneable是一个标记接口,没有任何方法。
(2)类似 Cloneable 的还有:RandomAccess(集合快速访问)、Serializable (序列化)。
(3)它们的作用就是当某个类实现这个接口时,我们就认为这个类拥有了接口标记的某种功能。
(4)java.lang.Object 本就有 clone() 方法(如下):
protected native Object clone() throws CloneNotSupportedException;
但若没实现 Cloneable 标记接口,也会抛出 CloneNotSupportedException 异常。
注:native方法是非Java代码实现的方法。
*/
public class PictureScroll implements Cloneable{
// 画长
private String length;
// 画宽
private String width;
// 画家
private Painter painter;
// 省略 getter / setter
// 实现clone()方法实现浅克隆
public PictureScroll clone(){
try {
Object obj = super.clone();
return (PictureScroll)obj;
} catch (CloneNotSupportedException e) {
return null;
}
}
}
/**
* A class implements the <code>Cloneable</code> interface to
* indicate to the {@link java.lang.Object#clone()} method that it
* is legal for that method to make a
* field-for-field copy of instances of that class.
*
* (译):类实现 Cloneable接口,以向 clone() 方法指示该方法为该类的实例拷贝字段是合法的。
* ...
*/
public interface Cloneable {
}
// 测试
public class Test{
public static void main(String[] args){
PictureScroll originalPictureScroll = new PictureScroll();
Painter painter = new Painter();
painter.setName("张择端");
originalPictureScroll.setPainter(painter);
originalPictureScroll.setWidth("24.8厘米");
originalPictureScroll.setLength("528.7厘米");
// 用原型实例(originalPictureScroll)指定创建对象的种类,并且通过拷贝这些原型创建新的对象(copyPictureScroll)。
PictureScroll copyPictureScroll = originalPictureScroll.clone();
System.out.println("画家:" + copyPictureScroll.getPainter().getName() +
";宽:" + copyPictureScroll.getWidth() +
";长:" + copyPictureScroll.getLength());
// 画家:张择端;宽:24.8厘米;长:528.7厘米
System.out.println(originalPictureScroll == copyPictureScroll); // false
System.out.println(originalPictureScroll.getPainter() == copyPictureScroll.getPainter()); // true
}
}
注意区分浅克隆/深克隆
(或者说 浅拷贝/深拷贝
、浅复制/深复制
)。
java.lang.Object
提供了一个对象拷贝的默认方法 clone
方法,但是该方法是有缺陷的,它提供了一种浅拷贝
方式,也就是它并不会把对象所有属性全部拷贝一份,而是有选择性的拷贝,拷贝规则如下:
1、基本类型
如果变量是基本类型,则拷贝其值,比如:int、float、long等。
2、String字符串
这个比较特殊,拷贝的是地址,是个引用,但是在修改的时候,它会从字符串池(String Pool)中重新生成新的字符串,原有的字符串对象保持不变,此处可以认为 String 是个基本类型。
3、对象
如果变量时一个实例对象,则拷贝地址引用,也就是说此时新拷贝出的对象与原有对象共享该实例变量,不受访问权限的限制。这在 Java 中很疯狂,因为它突破了访问权限的定义,一个 private 修饰的变量,竟然可以被两个实例对象访问。