先看一个简单案例

public class Test {
    public static void main(String args[]) {
        Student stu1 = new Student();
        stu1.number = 1;
        Student stu2 = stu1;//stu1和stu2指向堆内存中同一个对象
        System.out.println("学生1:" + stu1.number + "    学生2:" + stu2.number);
        stu2.number = 2;
        System.out.println("学生1:" + stu1.number + "    学生2:" + stu2.number);
        System.out.println(stu1 == stu2);
    }
}
class Student {
    public int number;
}

如上这种形式,仅仅将一个对象的引用赋给另一个引用,并没有复制出另一个对象,这两个引用指向的是内存中的同一个对象
所以,这根本不叫对象的复制

对象的复制(浅复制)

public class Test {
    public static void main(String args[]) {
        Student stu1 = new Student();
        stu1.number = 1;
        Student stu2 = (Student) stu1.clone();
        System.out.println("学生1:" + stu1.number + "    学生2:" + stu2.number);
        stu2.number = 2;
        System.out.println("学生1:" + stu1.number + "    学生2:" + stu2.number);
        System.out.println(stu1 == stu2);
    }
}
class Student implements Cloneable {
    public int number;
    @Override
    public Object clone() {
        Student stu = null;
        try {
            stu = (Student) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return stu;
    }
}

Object有个protected的clone方法,该方法的签名是:
protected native Object clone() throws CloneNotSupportedException;
要想对一个对象进行复制,就需要覆盖clone方法,一般步骤是(浅复制):
  • 1、被复制的类需要实现Clonenable接口,不实现的话在调用clone方法会抛出CloneNotSupportedException异常,该接口为标记接口(不含任何方法)
  • 2、覆盖clone()方法,访问修饰符设为public。方法中调用super.clone()方法得到需要的复制对象(native为本地方法)

浅复制可能出现的问题

public class Test {
    public static void main(String args[]) {
        Student stu1 = new Student();
        stu1.number = 1;
        stu1.address = new Address("广州");
        stu1.courseList.add("语文");

        //复制stu1
        Student stu2 = (Student) stu1.clone();
        System.out.println("学生1:" + stu1.number + "    " + stu1.address + "    " + stu1.courseList);
        System.out.println("学生2:" + stu2.number + "    " + stu2.address + "    " + stu2.courseList);

        //更改stu2
        stu2.number = 2;
        stu2.address = new Address("深圳");
        stu2.courseList.add("数学");
        System.out.println("学生1:" + stu1.number + "    " + stu1.address + "    " + stu1.courseList);
        System.out.println("学生2:" + stu2.number + "    " + stu2.address + "    " + stu2.courseList);
    }
}
class Student implements Cloneable {
    public int number;
    public ArrayList<String> courseList = new ArrayList<String>();
    public Address address;
    @Override
    public Object clone() {
        Student stu = null;
        try {
            stu = (Student) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return stu;
    }
}
class Address {
    public String add;
    public Address(String add) {
        this.add = add;
    }
}

更改stu2的address和courseList后,是不是发现,stu1的相应值也变了?这是为什么呢?
这是因为Java做了一个偷懒的拷贝动作,Object类提供的方法clone只是拷贝本对象,其对象内部的数组、引用对象等都不拷贝,还是指向原生对象的内部元素的地址,这种拷贝就叫做浅拷贝。
确实是非常浅,两个对象共享了一个私有变量,你改我改大家都能改,是一个种非常不安全的方式,在实际项目中使用还是比较少的。
注意:八大基本类型和String(虽然String 是引用类型,但Java其实是希望你把它也"认为"是基本类型,String 是没有 clone 方法的)等都会被拷贝的。

深复制

public class Test {
    public static void main(String args[]) {
        Student stu1 = new Student();
        stu1.number = 1;
        stu1.address = new Address("广州");
        stu1.courseList.add("语文");
        //复制stu1
        Student stu2 = (Student) stu1.clone();
        System.out.println("学生1:" + stu1.number + "    " + stu1.address + "    " + stu1.courseList);
        System.out.println("学生2:" + stu2.number + "    " + stu2.address + "    " + stu2.courseList);
        //更改stu2
        stu2.number = 2;
        stu2.address = new Address("深圳");
        stu2.courseList.add("数学");
        System.out.println("学生1:" + stu1.number + "    " + stu1.address + "    " + stu1.courseList);
        System.out.println("学生2:" + stu2.number + "    " + stu2.address + "    " + stu2.courseList);
    }
}
class Student implements Cloneable {
    public int number;
    public ArrayList<String> courseList = new ArrayList<String>();
    public Address address;
    @SuppressWarnings("unchecked")
    @Override
    public Object clone() {
        Student stu = null;
        try {
            stu = (Student) super.clone();//浅复制 
            stu.address = (Address) address.clone(); //深度复制
            stu.courseList = (ArrayList<String>) courseList.clone();//深度复制
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return stu;
    }
}
class Address implements Cloneable {//为了达到真正的复制对象,而不是纯粹引用复制。我们需要将Address类可复制化
    public String add;
    public Address(String add) {
        this.add = add;
    }
    @Override
    public Object clone() {
        Address addr = null;
        try {
            addr = (Address) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return addr;
    }
}


Java中的浅复制和深复制 Cloneable clone的更多相关文章

  1. JAVA中浅复制与深复制 - coolmist - ITeye技术网站

    body{ font-family: "Microsoft YaHei UI","Microsoft YaHei",SimSun,"Segoe UI& ...

  2. Java中引用的浅复制和深复制

    Java中除了基本类型int,char,double等的赋值是按照值传递之外,其余的类型和对象都是按照引用进行传递的. 下面来看一个关于引用的例子. package referenceCopy;// ...

  3. JAVA中浅复制与深复制

    1.浅复制与深复制概念⑴浅复制(浅克隆)被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象.换言之,浅复制仅仅复制所考虑的对象,而不复制它所引用的对象. ⑵深复 ...

  4. Java中的“浅复制”与“深复制”

    复制 将一个对象的引用复制给另一个对象,一共有三种方式.第一种方式是直接赋值,第二种方式是浅复制,第三种方式是深复制. 1.直接赋值 在Java中,A a1 = a2,这实际上复制的是引用,也就是说 ...

  5. java基础-浅复制与深复制的理解

    浅复制与深复制在很多编程语言中都有出现,那么什么是浅复制,什么是深复制呢? 要区分浅复制与深复制,首先我们要明确什么是复制,怎样才算是复制.复制的例子在生活中也随处可见,如复印一份文档,复制一段文字等 ...

  6. Java里的浅复制与深复制

    1.浅复制与深复制概念 ⑴浅复制(浅克隆) 被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象.换言之,浅复制仅仅复制所考虑的对象,而不 复制它所引用的对象. ...

  7. 深度解析javascript中的浅复制和深复制

    原文:深度解析javascript中的浅复制和深复制 在谈javascript的浅复制和深复制之前,我们有必要在来讨论下js的数据类型.我们都知道有Number,Boolean,String,Null ...

  8. js中的浅复制和深复制

    浅复制:浅复制是复制引用,复制后的引用都是指向同一个对象的实例,彼此之间的操作会互相影响 深复制:深复制不是简单的复制引用,而是在堆中重新分配内存,并且把源对象实例的所有属性都进行新建复制,以保证深复 ...

  9. Python中的浅复制、深复制

    参考 https://docs.python.org/3/library/copy.html?highlight=copy%20copy#copy.copy https://en.wikipedia. ...

  10. php对象复制、clone、浅复制与深复制实例详解

    php对象复制.clone.浅复制与深复制实例详解 一.用clone(克隆)来复制对象$obj1 = new Object();$obj2 = clone $obj1;clone方法会触发对象里定义的 ...

随机推荐

  1. python操作memcache

            48.python 操作memcached                  Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载.它通过在内存 ...

  2. unix环境高级编程-读书笔记与习题解答-第一篇

    从这周开始逐渐的进入学习状态,每天晚上都会坚持写c程序,并且伴随对这本书的深入,希望能写出更高质量的读书笔记和程序. 本书的第一章,介绍了一些关于unix的基础知识,在这里我不想去讨论linux到底是 ...

  3. 黑马程序员—C语言的特点和关键字

    ------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- C语言的简介 一. C语言具有下列特点: C语言既具有低级语言直接操纵硬件的特点,又具有高级语言 ...

  4. IOS--UISlider的使用方法

    IOS--UISlider的使用方法 // UISlider的常用方法 UISlider *oneSlider = [[UISlider alloc] init]; // 最常用 oneSlider. ...

  5. iOS9 以上的真机调试 不用证书

    具体流程如下: 首次使用AppleID  的注意事项:  要在设置中 进行 如下操作  设置--通用--描述文件   ---添加信任 但是有时候  还是 会不能调试,  显示信息  是这样的   : ...

  6. ps使用方法续

    1.找一张皱折的背景,将需要制作的照片拖入背景层,调整尺寸并裁剪,使之 与背景边框相配, 2.调整-色相饱和度,全图:饱和度-35,明度+10, 3.调整图层改成柔光模式,出来旧照片的效果了, 4.色 ...

  7. 【Java】Java Socket编程(1)基本的术语和概念

    计算机程序能够相互联网,相互通讯,这使一切都成为可能,这也是当今互联网存在的基础.那么程序是如何通过网络相互通信的呢?这就是我记录这系列的笔记的原因.Java语言从一开始就是为了互联网而设计的,它为实 ...

  8. Javascript 注意点

    prototype有助于减少function的冲突. 闭包有助于避免全部变量. this, prototype有助于实例化多个对象. 函数 函数表达式

  9. codeforces C. Mashmokh and Numbers

    题意:给你n和k,然后让你找出n个数使得gcd(a1,a2)+gcd(a3,a4)+......的和等于k: 思路:如果n为奇数,让前n-3个数的相邻两个数都为1,n-2和n-1两个数gcd为k-an ...

  10. cf E. George and Cards

    http://codeforces.com/contest/387/problem/E 题意:给你n个数,然后在输入k个数,这k个数都在n个数中出现,进行每一次操作就是在n个数中选择长度为w的连续序列 ...