欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Java的clone方法--深拷贝和浅拷贝

程序员文章站 2022-05-20 09:39:36
...

Cloneable接口是一个标记接口,也就是没有任何内容,定义如下:

clone方法是在Object种定义的,而且是protected型的,只有实现了这个接口,才可以在该类的实例上调用clone方法,否则会抛出CloneNotSupportExceptionObject中默认的实现是一个浅拷贝,也就是表面拷贝,如果需要实现深层次拷贝的话,必须对类中可变域生成新的实例

Object提供了一个对象拷贝的默认方法clone方法,但是该方法是有缺陷的,它提供了一种浅拷贝方式,也就是它并不会把对象所有属性全部拷贝一份,而是有选择性的拷贝,拷贝规则如下:

1、基本类型

如果变量是基本类型,则拷贝其值,比如:intfloatlong等。

2、String字符串

这个比较特殊,拷贝的是地址,是个引用,但是在修改的时候,它会从字符串池(String Pool)中重新生成新的字符串,原有的字符串对象保持不变,此处可以认为String是个基本类型。

3、对象

如果变量时一个实例对象,则拷贝地址引用,也就是说此时新拷贝出的对象与原有对象共享该实例变量,不受访问权限的限制。

总结一下:

浅层复制: 被复制的对象的所有成员属性都有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。换言之,浅层复制仅仅复制所考虑的对象,而不复制它所引用的对象。

深层复制:被复制对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量。那些引用其他对象的变量将指向被复制过的新对象,而不是原有的那些被引用的对象。换言之,深层复制要复制的对象  所引用的对象都复制一遍。

举个例子:

public class Client {
    public static void main(String[] args){
        //定义父亲
        Person p = new Person("父亲");
        //定义大儿子
        Person son1 = new Person("大儿子",p);
        //定义小儿子
        Person son2 = son1.clone();
        //重新给son2起名
        son2.setName("小儿子");
           
        //给小儿子,找个干爹
        son2.getFather().setName("干爹");
           
        System.out.println(son1.getName()+" 的父亲是 "+son1.getFather().getName());
        System.out.println(son2.getName()+" 的父亲是 "+son2.getFather().getName());
    }
}
class Person implements Cloneable{
       
    private String name;
       
    private Person father;
       
    public Person(String name){
        this.name=name;
    }
       
    public Person(String name,Person father){
        this.name=name;
        this.father=father;
    }
       
    //拷贝的实现
    @Override
    public Person clone(){
        Person p = null;
        try{
            //调用Object的浅拷贝
            p = (Person) super.clone();
               
            /**
             * 1.重新覆写对象实例部分的拷贝,实现深拷贝
             * 2.如果没有重写对象实例部分的拷贝,那么大儿子和小儿子的父亲会引用同一个父亲,
             * 只要任意修改一下父亲,另外一个就会被修改
             */
            p.setFather(new Person(p.getFather().getName()));
        }catch(CloneNotSupportedException e){
            e.printStackTrace();
        }
        return p;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Person getFather() {
        return father;
    }
    public void setFather(Person father) {
        this.father = father;
    }
}