黑马程序员技术交流社区

标题: 【上海校区】Java 拷贝 [打印本页]

作者: 不二晨    时间: 2018-11-30 10:42
标题: 【上海校区】Java 拷贝
粗略介绍
Object 类中有个受保护方法 clone,所以很多时候我们都可以在类中重写 clone 方法。调用该方法会将对象复制一份,创造一个新的对象,但是这里就需要注意了。
Object 中存在 clone 方法,由于是受保护的,要使用对象的 clone 方法,还需要重写该方法,但是光是重写该方法并没用,还需要让 Java 虚拟机知道该类是支持 clone的,所以类需要实现 Cloneable 接口。
不实现 Cloneable 接口,而调用 clone 方法,会报错:
关于 clone ,最主要的应该还是浅拷贝和深拷贝。

浅拷贝
ShallowCopy.java
public class ShallowCopy implements Cloneable {    private String name;    private ArrayList<String> list = new ArrayList<>();    public void printlnName() {        System.out.println(this.name);    }    public void setName(String name) {        this.name = name;    }    public void addListValue(String value) {        this.list.add(value);    }    public void printlnList() {        System.out.println(this.list);    }    public ShallowCopy() {        System.out.println("shallow copy test");    }    @Override    protected ShallowCopy clone() throws CloneNotSupportedException {        return (ShallowCopy) super.clone();    }    public static void main(String[] args) throws CloneNotSupportedException {        ShallowCopy shallow = new ShallowCopy();        shallow.setName("yhx");        shallow.addListValue("Java");                shallow.printlnName();  // 输出 yhx        shallow.printlnList();  // 输出 Java                ShallowCopy shallowCopy = shallow.clone(); // 克隆        // 打印出两个对象的地址        System.out.println(shallow);        System.out.println(shallowCopy);                shallowCopy.printlnList(); // 输出 Java                shallowCopy.addListValue("Python");        shallowCopy.printlnList(); // 输出 Java,Python        shallowCopy.printlnName(); // 输出 yhx                shallowCopy.setName("hello");        shallow.printlnName(); // 输出 yhx        shallow.printlnList(); // // 输出 Java,Python    }}
从结果中我们可以看到


像这种只拷贝了对象本身,而对象中引用数据类型没有被拷贝的拷贝方式,叫做浅拷贝。
浅拷贝往往存在一定的风险,因为引用对象的地址拷贝前后一致,所以对象的值很容易被更改,不安全。

深拷贝
将上面的代码简单修改下就成了深拷贝
DeepCopy.java
public class DeepCopy implements Cloneable{    private String name;    private ArrayList<String> list = new ArrayList<>();    public void printlnName() {        System.out.println(this.name);    }    public void setName(String name) {        this.name = name;    }    public void addListValue(String value) {        this.list.add(value);    }    public void printlnList() {        System.out.println(this.list);    }    public DeepCopy() {        System.out.println("deep copy test");    }    @Override    protected DeepCopy clone() throws CloneNotSupportedException {        DeepCopy clone = (DeepCopy) super.clone();        clone.list = (ArrayList<String>) this.list.clone();        return clone;    }    public static void main(String[] args) throws CloneNotSupportedException {        DeepCopy deep = new DeepCopy();        deep.setName("yhx");        deep.addListValue("Java");        deep.printlnName();         deep.printlnList();          DeepCopy DeepCopy = deep.clone(); // 克隆        // 打印出两个对象的地址        System.out.println(deep);        System.out.println(DeepCopy);        DeepCopy.printlnList();         DeepCopy.addListValue("Python");        DeepCopy.printlnList();         DeepCopy.printlnName();         DeepCopy.setName("hello");        deep.printlnName();         deep.printlnList();     }}
打印结果:

可以看到,原先对象中 list 的值并不会因为拷贝对象的 list 值改变而改变,因为它们存于两个不同的内存了,不会共享。
Note:
如果字段上有 final 修饰,就不能实现 clone 方法了,因为 final 变量不能再次被赋值。


应用场景
原型模式中会使用到拷贝。


作者: 不二晨    时间: 2018-12-5 16:27





欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2