对象的复制(浅复制与深复制)

在Java中如果想将一个基本类型变量的值赋给另一个变量,直接使用等号解可以了,原始的版本改变了,副本并不会发生变化,如下:

int a=10;
int b=a;
a=9;
System.out.println(a); //9
System.out.println(b); //10

但是如果想要复制的变量不是基本类型,而是引用类型的话,就会与上面的效果不同:

package demos;
/**
 * Created by hu on 2016/3/26.
 */
public class People {
    private int age;
    private String name;
    public People(int age,String name){
        this.age=age;
        this.name=name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
    public String toString(){
        return this.name+" is "+this.age;
    }
    public static void main(String[] args){
        People p1=new People(12,"tom");
        People p2=p1;
        System.out.println(p1);
        System.out.println(p2);
        p1.setAge(25);
        p1.setName("jack");
        System.out.println(p1);
        System.out.println(p2);
    }
}
/*output:
* tom is 12
* tom is 12
* jack is 25
* jack is 25
* */     

在上面的代码中,原始对象发生变化,副本对象也发生了变化,这是因为,执行p2=p1这段代码的时候,只是发生了引用变量的复制,而并没有发生对象的复制,两个引用变量指向的还是同一个对象。

那么,怎样才能达到复制一个对象呢?
  是否记得万类之王Object。它有11个方法,有两个protected的方法,其中一个为clone方法。
该方法的签名是:

protected native Object clone() throws CloneNotSupportedException;

一般步骤是(浅复制):

1. 被复制的类需要实现Clonenable接口(不实现的话在调用clone方法会抛出CloneNotSupportedException异常) 该接口为标记接口(不含任何方法)

2. 覆盖clone()方法,访问修饰符设为public。方法中调用super.clone()方法得到需要的复制对象,(native为本地方法)

对上面的代码进行改造,如下:

package demos;
/**
 * Created by hu on 2016/3/26.
 */
public class People implements Cloneable{
    private int age;
    private String name;
    public People(int age,String name){
        this.age=age;
        this.name=name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
    public String toString(){
        return this.name+" is "+this.age;
    }
    @Override
    public Object clone(){
        People people = null;
        try{
            people = (People)super.clone();
        }catch(CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return people;
    }
    public static void main(String[] args){
        People p1=new People(12,"tom");
        People p2= (People) p1.clone();
        System.out.println(p1);
        System.out.println(p2);
        p1.setAge(25);
        p1.setName("jack");
        System.out.println(p1);
        System.out.println(p2);
    }
}
/*output:
* tom is 12
* tom is 12
* jack is 25
* tom is 12
* */

那么我们还可以在People中再添加一个Address类,如下:

package demos;
/**
 * Created by hu on 2016/3/26.
 */
class Address{
    private String address;
    public Address(String address){
        this.address=address;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString(){
        return address;
    }
}
public class People implements Cloneable{
    private int age;
    private String name;
    private Address address;

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

    public People(int age,String name){
        this.age=age;
        this.name=name;
    }
    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
    public String toString(){
        return this.name+" is "+this.age+", live in "+address;
    }
    @Override
    public Object clone(){
        People people = null;
        try{
            people = (People)super.clone();
        }catch(CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return people;
    }
    public static void main(String[] args){
        Address address=new Address("LuoYang");
        People p1=new People(12,"tom");
        p1.setAddress(address);
        People p2= (People) p1.clone();
        System.out.println(p1);
        System.out.println(p2);
        p1.setAge(25);
        p1.setName("jack");
        address.setAddress("ZhengZhou");
        System.out.println(p1);
        System.out.println(p2);
    }
}
/*output:
* tom is 12, live in LuoYang
* tom is 12, live in LuoYang
* jack is 25, live in ZhengZhou
* tom is 12, live in ZhengZhou
* */

上面的代码,原始的版本对象地址发生了变化,但是副本却没有发生变化,那是因为在进行复制时,只复制了address这个变量的引用,并没有复制该变量指向的对象。此时就需要深度复制,深度复制很简单,只需要将Address也实现Cloneable接口即可,修改如下:

package demos;
/**
 * Created by hu on 2016/3/26.
 */
class Address implements Cloneable{
    private String address;
    public Address(String address){
        this.address=address;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString(){
        return address;
    }
    @Override
    public Object clone(){
        Address address = null;
        try{
            address = (Address)super.clone();
        }catch(CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return address;
    }
}
public class People implements Cloneable{
    private int age;
    private String name;
    private Address address;

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

    public People(int age,String name){
        this.age=age;
        this.name=name;
    }
    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
    public String toString(){
        return this.name+" is "+this.age+", live in "+address;
    }
    @Override
    public Object clone(){
        People people = null;
        try{
            people = (People)super.clone();
        }catch(CloneNotSupportedException e) {
            e.printStackTrace();
        }
        people.setAddress((Address) people.getAddress().clone());
        return people;
    }
    public static void main(String[] args){
        Address address=new Address("LuoYang");
        People p1=new People(12,"tom");
        p1.setAddress(address);
        People p2= (People) p1.clone();
        System.out.println(p1);
        System.out.println(p2);
        p1.setAge(25);
        p1.setName("jack");
        address.setAddress("ZhengZhou");
        System.out.println(p1);
        System.out.println(p2);
    }
}
/*output:
* tom is 12, live in LuoYang
* tom is 12, live in LuoYang
* jack is 25, live in ZhengZhou
* tom is 12, live in LuoYang
* */

  如此,就是深度复制了。

总结:浅拷贝是指在拷贝对象时,对于基本数据类型的变量会重新复制一份,而对于引用类型的变量只是对引用进行拷贝,没有对引用指向的对象进行拷贝。而深拷贝是指在拷贝对象时,同时会对引用指向的对象进行拷贝。区别就在于是否对对象中的引用变量所指向的对象进行拷贝。

时间: 2024-10-08 14:17:53

对象的复制(浅复制与深复制)的相关文章

iOS 浅赋值、深复制、完全复制的知识点梳理验证(附加归档解档)

写于前: 在之前转载的一片文章中,文中对浅复制和深复制进行了详细的解读,同时还提到了深复制(one-level-deep copy).完全复制(true copy)的概念,并指出iOS开发中的深复制是单层深赋值,本文将对这几个概念进行验证梳理. (单层和完全概念区分:例如多层数组只实现一层内容拷贝,其他层为指针拷贝成为单层深复制:若多层内容都实现拷贝称为完全赋值) 程序中用到的几点概念补充 (1) 浅复制(shallow copy):在浅复制操作时,对于被复制对象的每一层都是指针复制. 深复制(

iOS 集合的深复制与浅复制

概念 对象拷贝有两种方式:浅复制和深复制.顾名思义,浅复制,并不拷贝对象本身,仅仅是拷贝指向对象的指针:深复制是直接拷贝整个对象内存到另一块内存中. 一图以蔽之 再简单些说:浅复制就是指针拷贝:深复制就是内容拷贝. 集合的浅复制 (shallow copy) 集合的浅复制有非常多种方法.当你进行浅复制时,会向原始的集合发送retain消息,引用计数加1,同时指针被拷贝到新的集合. 现在让我们看一些浅复制的例子: NSArray *shallowCopyArray = [someArray cop

也来谈一谈js的浅复制和深复制

1.浅复制VS深复制 本文中的复制也可以称为拷贝,在本文中认为复制和拷贝是相同的意思.另外,本文只讨论js中复杂数据类型的复制问题(Object,Array等),不讨论基本数据类型(null,undefined,string,number和boolean),这些类型的值本身就存储在栈内存中(string类型的实际值还是存储在堆内存中的,但是js把string当做基本类型来处理 ),不存在引用值的情况. 浅复制和深复制都可以实现在已有对象的基础上再生一份的作用,但是对象的实例是存储在堆内存中然后通

深复制与浅复制

概念 对象拷贝有两种方式:浅复制和深复制.顾名思义,浅复制,并不拷贝对象本身,仅仅是拷贝指向对象的指针:深复制是直接拷贝整个对象内存到另一块内存中. 一图以蔽之 再简单些说:浅复制就是指针拷贝:深复制就是内容拷贝. 集合的浅复制 (shallow copy) 集合的浅复制有非常多种方法.当你进行浅复制时,会向原始的集合发送retain消息,引用计数加1,同时指针被拷贝到新的集合. 现在让我们看一些浅复制的例子: NSArray *shallowCopyArray = [someArray cop

iOS中的深复制与浅复制

很多语言中都有深复制浅复制的概念,如C++,ObjC等.简单来说,浅复制就是两个变量指向了同一块内存区域,深复制就是两个变量指向了不同的内存区域,但是两个内存区域里面的内容是一样的. 浅复制示意图: 深复制示意图: iOS开发中,浅复制和深复制要更复杂一些,涉及到集合对象和非集合对象的copy与mutableCopy. 非集合对象:如NSString,NSInteger,NSNumber…… 集合对象:如NSArray,NSDictionary,…… 1:非集合对象的copy与mutableCo

OC 中 的copy 功能 深复制 和 浅复制 的 区别

系统的类要是实现copy拷贝的功能,必须先签订拷贝NSCopying的协议,然后实现对应的方法 在.h文件中得@interface Boy : NSObject 的后面需要签订拷贝NSCopying的协议 例子: 在.h文件中 @interface Boy : NSObject<NSCopying> 1. Boy类使用copy的方法 例子: Boy *boy =[Boy boyWithName:@"zhangyangyang" hobby:@"wan"]

.NET中深复制与浅复制

概述: 在.NET里面,提供对象复制的功能,前提是实现ICloneable接口.ICloneable接口中有一个Clone方法, 可以在类中覆写实现自定义的拷贝方法.对象复制的实现方法有两种:深复制和浅复制. 深复制和浅复制: 浅复制,浅复制是指源对象与复制出来的对象共用一份实体,对其中任何一个对象的改动都会影响另外一个对象.相当于复制了指针. 深复制:指源对象与复制对象互相独立,为新对象重新分配了一段内存空间,并复制源对象的内容.其中任何一个对象的改动都不会对另外一个对象造成影响. 深浅复制与

C++学习基础七——深复制与浅复制

一.深复制与浅复制基本知识 深复制和浅复制,又称为深拷贝和浅拷贝. 深复制和浅复制的区别如下图1所示: 图1 图1表示的是,定义一个类CDemo,包含int a和char *str两个成员变量, 当深复制时,A中的指针str与B中的指针str指向不同的地址,只是地址所指向的数据相同. 当浅复制时,A中的指针str与B中的指针str指向相同的地址. 1.浅复制:如果我们自己不实现复制构造函数,则C++会自动合成一个复制构造函数,又称为浅复制构造函数. 2.深复制:如果使用指针或者系统资源(如数据库

深复制 浅复制

深复制:不仅复制对象 还复制对象关联的对象 浅复制:只是复制对象本身 不复制对象关联的对象 // // main.m // 对象的复制 // // Created by MAC on 15/12/20. // Copyright © 2015年 MAC. All rights reserved. // #import <Foundation/Foundation.h> #import "Person.h" int main(int argc, const char * ar

面向对象之深复制与浅复制

前言: 基于面向对象的思想,大部分的类都可视为“工具”.那么对于工具的使用,我们总是期望能高效而又方便.特别是当我们在重复实现某些功能的时候,那有没有一种能快速复用类的捷径呢? 既然提出来,答案当然是肯定的.“Copy”----复制. 查看Java中的Object这个祖先类我们可以发现,该类含有一个clone()方法,并且返回“Object”类型.不过,方法的前面还有“native”关键字,其表示Object类使用其方法时是编译器内部执行的,对外界不可正常访问. 回到正题,什么样的类才可以进行克