文档章节

java对象的浅拷贝和深拷贝

一切尽在不言中
 一切尽在不言中
发布于 2018/12/10 16:08
字数 1516
阅读 6
收藏 0

浅拷贝

java的数据类型有基本数据类型(如:int、long等)和引用数据类型。例如:对象1中有属性a(基本数据类型)和属性b(引用数据类型),在进行浅拷贝到对象2时,属性a复制属性的值给对象2,这样对象1和对象2修改属性a时不会相互影响。属性b则是复制一份引用(即内存地址)给对象2,这样对象1修改属性b后,对象2中的值也会改变。

一般通过Object的clone( )方法来实现浅复制,使用clone( )方法需要实现Cloneable接口。

clone( )方法的基本规则如下:

1、基本数据类型

进行值的拷贝,例如:int、long、byte等。

2、String

如果变量是String类型,则拷贝其地址引用,但是因为java中String是不变的,所以在修改的时候是新建一个String,这样新对象指向新地址不影响旧对象的值。

3、对象

对象的拷贝是复制其引用地址,即新对象和原来对象共用一个对象实例。

package com.hs.copy;

public class Age {

    private int age;
    
    

    public Age(int age) {
        super();
        this.age = age;
    }

    /* (non-Javadoc)
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        return "Age [age=" + age + "]";
    }

    /**
     * @return the age
     */
    public int getAge() {
        return age;
    }

    /**
     * @param age the age to set
     */
    public void setAge(int age) {
        this.age = age;
    }
    
}

 

package com.hs.copy;

public class Person implements Cloneable{

    private String name;
    
    private Age age;
    
    public Person(String name, int age) {
        super();
        this.name = name;
        this.age = new Age(age);
    }

    public Person clone(){
        
        try {
            
            return (Person)super.clone();
            
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return null;
        
    }
    
    

    /* (non-Javadoc)
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        return "Person [name=" + name + ", age=" + age.getAge() + "]";
    }



    /**
     * @return the name
     */
    public String getName() {
        return name;
    }

    /**
     * @param name the name to set
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * @return the age
     */
    public Age getAge() {
        return age;
    }

    /**
     * @param age the age to set
     */
    public void setAge(Age age) {
        this.age = age;
    }
    
    
    
}

 

package com.hs.copy;

/**
 * 浅拷贝
 * @author Administrator
 *
 */
public class ShallowCopy {

    public static void main(String[] args) {
        
        Person person1 = new Person("yang", 18);
        System.out.println( "person1 : " + person1.toString() );
        
        Person person2 = person1.clone();
        System.out.println( "person2 : " + person2.toString() );
        
        person2.setName("yyyy");
        System.out.println();
        System.out.println( "-----修改基本类型变量后-----");
        System.out.println( "person1 : " + person1.toString() );
        System.out.println( "person2 : " + person2.toString() );
        
        person2.getAge().setAge(20);
        System.out.println();
        System.out.println( "-----修改引用类型变量后-----");
        System.out.println( "person1 : " + person1.toString() );
        System.out.println( "person2 : " + person2.toString() );
        
    }

}

运行结果:

person1 : Person [name=yang, age=18]
person2 : Person [name=yang, age=18]

-----修改基本类型变量后-----
person1 : Person [name=yang, age=18]
person2 : Person [name=yyyy, age=18]

-----修改引用类型变量后-----
person1 : Person [name=yang, age=20]
person2 : Person [name=yyyy, age=20]

 

深拷贝

通过上面的学习,很容易发现浅拷贝有个缺陷,即变量是引用类型时并没有实现值的拷贝。这时候就要用到深拷贝来实现了。如下是深拷贝的两种实现。

一、将引用类型的变量以及变量的变量全部实现clone( )方法

该实现的缺点:当引用类型的变量很多、很深时,代码量很大

package com.hs.copy;

public class Age implements Cloneable{

    private int age;
    
    

    public Age(int age) {
        super();
        this.age = age;
    }
    
    

    /* (non-Javadoc)
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        return "Age [age=" + age + "]";
    }

    /**
     * 深拷贝-新增
     */
    public Age clone(){
        
        try {
            return (Age)super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return null;
        
    }

    /**
     * @return the age
     */
    public int getAge() {
        return age;
    }

    /**
     * @param age the age to set
     */
    public void setAge(int age) {
        this.age = age;
    }
    
    
    
}

 

package com.hs.copy;

public class Person implements Cloneable{

    private String name;
    
    private Age age;
    
    public Person(String name, int age) {
        super();
        this.name = name;
        this.age = new Age(age);
    }

    /**
     * 深拷贝
     */
    public Person clone(){
        
        try {
            
            Person person = (Person)super.clone();
            Age age = person.age.clone();
            person.setAge(age);
            return person;
            
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return null;
        
    }
    
    
    /**
     * 浅拷贝
     */
    /*public Person clone(){
        
        try {
            
            return (Person)super.clone();
            
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return null;
        
    }*/
    
    

    /* (non-Javadoc)
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        return "Person [name=" + name + ", age=" + age.getAge() + "]";
    }



    /**
     * @return the name
     */
    public String getName() {
        return name;
    }

    /**
     * @param name the name to set
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * @return the age
     */
    public Age getAge() {
        return age;
    }

    /**
     * @param age the age to set
     */
    public void setAge(Age age) {
        this.age = age;
    }
    
    
    
}

 

package com.hs.copy;

/**
 * 深拷贝
 * @author Administrator
 *
 */
public class DeepCopy {

    public static void main(String[] args) {
        
        Person person1 = new Person("yang", 18);
        System.out.println( "person1 : " + person1.toString() );
        
        Person person2 = person1.clone();
        System.out.println( "person2 : " + person2.toString() );
        
        person2.setName("yyyy");
        System.out.println();
        System.out.println( "-----修改基本类型变量后-----");
        System.out.println( "person1 : " + person1.toString() );
        System.out.println( "person2 : " + person2.toString() );
        
        person2.getAge().setAge(20);
        System.out.println();
        System.out.println( "-----修改引用类型变量后-----");
        System.out.println( "person1 : " + person1.toString() );
        System.out.println( "person2 : " + person2.toString() );
        
    }

}

结果:

person1 : Person [name=yang, age=18]
person2 : Person [name=yang, age=18]

-----修改基本类型变量后-----
person1 : Person [name=yang, age=18]
person2 : Person [name=yyyy, age=18]

-----修改引用类型变量后-----
person1 : Person [name=yang, age=18]
person2 : Person [name=yyyy, age=20]

 

二、通过对象的序列化,再反序列化实现深拷贝

package com.hs.copy;

import java.io.Serializable;

public class AgeDeep implements Serializable{

    private int age;
    
    

    public AgeDeep(int age) {
        super();
        this.age = age;
    }
    
    

    /* (non-Javadoc)
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        return "Age [age=" + age + "]";
    }


    /**
     * @return the age
     */
    public int getAge() {
        return age;
    }

    /**
     * @param age the age to set
     */
    public void setAge(int age) {
        this.age = age;
    }
    
    
    
}

 

package com.hs.copy;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class PersonDeep implements Serializable {

    private String name;
    
    private AgeDeep age;
    
    public PersonDeep(String name, int age) {
        super();
        this.name = name;
        this.age = new AgeDeep(age);
    }

    public PersonDeep deepClone(){
        
        ObjectOutputStream objectOutputStream = null;
        ObjectInputStream objectInputStream = null;
        try {
            //序列化
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
            objectOutputStream.writeObject(this);
            
            //反序列化
            ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
            objectInputStream = new ObjectInputStream(byteArrayInputStream);
            return (PersonDeep)objectInputStream.readObject();
            
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }finally {
            try {
                if( objectOutputStream != null ){
                    objectOutputStream.close();
                }
                if( objectInputStream != null ){
                    objectInputStream.close();
                }
                
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
        
    }
    

    /* (non-Javadoc)
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        return "Person [name=" + name + ", age=" + age.getAge() + "]";
    }



    /**
     * @return the name
     */
    public String getName() {
        return name;
    }

    /**
     * @param name the name to set
     */
    public void setName(String name) {
        this.name = name;
    }




    /**
     * @return the age
     */
    public AgeDeep getAge() {
        return age;
    }




    /**
     * @param age the age to set
     */
    public void setAge(AgeDeep age) {
        this.age = age;
    }

    
    
    
}

 

package com.hs.copy;

/**
 * 深拷贝
 * @author Administrator
 *
 */
public class DeepCopy {

    
    
    /**
     * 序列化深拷贝
     * @param args
     */
    public static void main(String[] args) {
        
        PersonDeep person1 = new PersonDeep("yang", 18);
        System.out.println( "person1 : " + person1.toString() );
        
        PersonDeep person2 = person1.deepClone();
        System.out.println( "person2 : " + person2.toString() );
        
        person2.setName("yyyy");
        System.out.println();
        System.out.println( "-----修改基本类型变量后-----");
        System.out.println( "person1 : " + person1.toString() );
        System.out.println( "person2 : " + person2.toString() );
        
        person2.getAge().setAge(20);
        System.out.println();
        System.out.println( "-----修改引用类型变量后-----");
        System.out.println( "person1 : " + person1.toString() );
        System.out.println( "person2 : " + person2.toString() );
    }

}

 

两种深拷贝效率对比结果:用clone实现明显快于序列化

序列化:
count:10000 time:807ms
count:10000 time:835ms
count:10000 time:813ms
count:100000 time:1894ms
count:100000 time:1926ms
count:100000 time:1973ms
count:1000000 time:11313ms
count:1000000 time:10930ms
count:1000000 time:11016ms

clone():
count:10000 time:3ms
count:10000 time:7ms
count:10000 time:4ms
count:100000 time:13ms
count:100000 time:16ms
count:100000 time:14ms
count:1000000 time:43ms
count:1000000 time:38ms
count:1000000 time:40ms

 

© 著作权归作者所有

共有 人打赏支持
上一篇: java单例设计模式
下一篇: 模板设计模式
一切尽在不言中
粉丝 0
博文 12
码字总数 7752
作品 0
杭州
私信 提问
Java拾遗:008 - 对象克隆与浅拷贝、深拷贝

对象克隆 Object类中有一个方法叫,完整代码 首先它是一个Native方法,而且是受保护的(),抛出一个异常(JDK1.8)。 通常程序员自己定义的类不能直接调用方法,如果要在外部调用,需要重写...

一别丶经年
2018/08/04
0
0
Java中对象的浅拷贝与深拷贝

Java中的拷贝方式分为深拷贝和浅拷贝。简单来说,深拷贝就是把一个对象中的所有值,如果被拷贝对象中有对其他对象的引用,那么这个引用指向的对象本身会被重新创建。浅拷贝和深拷贝类似,但是...

夜默
2013/06/18
0
0
Java中如何克隆集合——ArrayList和HashSet深拷贝

编程人员经常误用各个集合类提供的拷贝构造函数作为克隆,,,或者其他集合实现的方法。需要记住的是,Java集合的拷贝构造函数只提供浅拷贝而不是深拷贝,这意味着存储在原始List和克隆List中...

markGao
2014/04/18
0
0
Java中如何克隆集合——ArrayList和HashSet深拷贝

编程人员经常误用各个集合类提供的拷贝构造函数作为克隆List,Set,ArrayList,HashSet或者其他集合实现的方法。需要记住的是,Java集合的拷贝构造函数只提供浅拷贝而不是深拷贝,这意味着存...

LCZ777
2014/04/14
0
0
我的Java设计模式-原型模式

“不好意思,我是卧底!哇哈哈哈~”额......自从写了上一篇的观察者模式,就一直沉浸在这个角色当中,无法自拨。昨晚在看《使徒行者2》,有一集说到啊炮仗哥印钞票,我去,这就是想印多少就印...

Jet啟思
2017/10/25
0
0

没有更多内容

加载失败,请刷新页面

加载更多

开始看《JSP&Servlet学习笔记》

1:WEB应用简介。其中1.2.1对Web容器的工作流程写得不错 2:编写Servlet。搞清楚了Java的Web目录结构,以及Web.xml的一些配置作用。特别是讲了@WebServlet标签 3:请求与响应。更细致的讲了从...

max佩恩
24分钟前
0
0
mysql分区功能详细介绍,以及实例

一,什么是数据库分区 前段时间写过一篇关于mysql分表的的文章,下面来说一下什么是数据库分区,以mysql为例。mysql数据库中的数据是以文件的形势存在磁盘上的,默认放在/mysql/data下面(可...

吴伟祥
24分钟前
0
0
SQL语句查询

1.1 排序 通过order by语句,可以将查询出的结果进行排序。放置在select语句的最后。 格式: SELECT * FROM 表名 ORDER BY 排序字段ASC|DESC; ASC 升序 (默认) DESC 降序 1.查询所有商品信息,...

stars永恒
41分钟前
2
0
IntelliJ IDEA 第一个 Scala 程序

IntelliJ 安装完成 Scala 插件后,你需要尝试使用 IntelliJ 来创建并且运行第一个程序。 通常这个程序只是简单的输出 Hello World。 创建一个新工程 在文件下面选择新建,然后选择创建工程。...

honeymose
45分钟前
2
0
csapp 习题 - 如何实现异或 exclusive-or

阅读 csapp v3 时,练习题 2.13 很有意思。练习题描述如下。 位设置是对于参数 mask 中每一个为 1 的位,那么参数 x 中相应位则被设置为 1 ;位清除是对于参数 mask 中每一个为 1 的位,那么...

ylme
昨天
6
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部