Java深浅拷贝分析

浅拷贝

浅拷贝是按位拷贝对象,它会创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值;如果属性是内存地址(引用类型),拷贝的就是内存地址,因此如果其中一个对象改变了这个地址,就会影响到另一个对象。
简而言之,浅拷贝仅仅复制锁考虑的对象,而不复制它所引用的对象。

实现浅拷贝的步骤是:
1、被复制的类需要实现Cloneable接口(不实现的话在调用clone方法会抛出CloneNotSupportedException异常)改接口为标记接口(不含任何方法)
2、覆盖clone()方法,访问修饰符设为public。方法中调用super.clone()方法得到需要的复制对象,(native为本地方法)

深拷贝

深拷贝还要吧一个对象中所引用的对象也要拷贝一遍。
下面是一个例子:

123456789101112131415161718192021222324252627282930313233343536
package JavaCoreTechnology;

import java.io.Serializable;

/** * Created by benjamin on 1/14/16. */public class User implements Serializable, Cloneable {    private static final long serialVersionUID = -3080870074068514966L;

private String userName;    private Dog dog;

public String getUserName() {        return userName;    }

public void setUserName(String userName) {        this.userName = userName;    }

public Dog getDog() {        return dog;    }

public void setDog(Dog dog) {        this.dog = dog;    }

public User clone() throws CloneNotSupportedException {        User user = (User)super.clone();        Dog d = dog.clone();    // 深拷贝必须克隆包含的对象        user.setDog(d);        return user;    }}
123456789101112131415161718192021222324
package JavaCoreTechnology;

import java.io.Serializable;

/** * Created by benjamin on 1/14/16. */public class Dog implements Serializable, Cloneable {    private static final long serialVersionUID = 8869944898908733919L;

private String dogName;

public String getDogName() {        return dogName;    }

public void setDogName(String dogName) {        this.dogName = dogName;    }

public Dog clone() throws CloneNotSupportedException {        return (Dog)super.clone();    }}
12345678910111213141516171819202122232425
package JavaCoreTechnology;

/** * Created by benjamin on 1/14/16. */public class CloneTest {

public static void main(String[] args) throws CloneNotSupportedException {        User user = new User();        Dog dog = new Dog();        dog.setDogName("D1");        user.setUserName("A1");        user.setDog(dog);

User user2 = user.clone();        user2.setUserName("A2");        user2.getDog().setDogName("D2");

System.out.println(user.getUserName()); // A1        System.out.println(user.getDog().getDogName()); // D1

System.out.println(user2.getUserName());    // A2        System.out.println(user2.getDog().getDogName());    // D2    }}

可以发现上面已经成功的实现了深拷贝。但是试想一下,要是我一个类当中使用到了100个对象,那我也要一个个的去那些对象里面实现clone的方法吗,这显然有些太麻烦了。

为此,我们可以使用序列化对象的方法得到对象的一个拷贝。这就要用到了输入输出流。
修改一下代码,我们再来看一下:

去掉所有实体的Cloneable实现,以及clone方法:

1234567891011121314151617181920212223242526272829
package JavaCoreTechnology;

import java.io.Serializable;

/** * Created by benjamin on 1/14/16. */public class User implements Serializable {    private static final long serialVersionUID = -3080870074068514966L;

private String userName;    private Dog dog;

public String getUserName() {        return userName;    }

public void setUserName(String userName) {        this.userName = userName;    }

public Dog getDog() {        return dog;    }

public void setDog(Dog dog) {        this.dog = dog;    }}
1234567891011121314151617181920
package JavaCoreTechnology;

import java.io.Serializable;

/** * Created by benjamin on 1/14/16. */public class Dog implements Serializable {    private static final long serialVersionUID = 8869944898908733919L;

private String dogName;

public String getDogName() {        return dogName;    }

public void setDogName(String dogName) {        this.dogName = dogName;    }}

增加一个工具方法用来clone对象:

123456789101112131415161718192021222324252627282930313233
package JavaCoreTechnology;

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

/** * Created by benjamin on 1/14/16. */public class ObjCloner {

public static <T> T cloneObj(T obj) {        T cloneVal = null;

try {

// 写入流中            ByteArrayOutputStream baos = new ByteArrayOutputStream();            ObjectOutputStream oos = new ObjectOutputStream(baos);            oos.writeObject(obj);

// 从流中读入对象            ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()));            cloneVal = (T)ois.readObject();

} catch (Exception e) {            e.printStackTrace();        }

return cloneVal;    }}
12345678910111213141516171819202122232425
package JavaCoreTechnology;

/** * Created by benjamin on 1/14/16. */public class CloneTest {

public static void main(String[] args) throws CloneNotSupportedException {        User user = new User();        Dog dog = new Dog();        dog.setDogName("D1");        user.setUserName("A1");        user.setDog(dog);

User user2 = ObjCloner.cloneObj(user);        user2.setUserName("A2");        user2.getDog().setDogName("D2");

System.out.println(user.getUserName()); // A1        System.out.println(user.getDog().getDogName()); // D1

System.out.println(user2.getUserName());    // A2        System.out.println(user2.getDog().getDogName());    // D2    }}

输出结果不变,总得看来,我更推荐大家使用流的方式来进行对象的深拷贝,不知道大家怎么看呢?

时间: 2024-10-31 21:30:06

Java深浅拷贝分析的相关文章

详解iOS的深浅拷贝_IOS

前言 OC对象的三种拷贝方式 OC的对象拷贝有如下三种方式,很多时候我们把深复制和完全复制混为一谈,其他他们是有区别的,具体如下 浅复制(shallow copy):在浅复制操作时,对于被复制对象的每一层都是指针复制. 深复制(one-level-deep copy):在深复制操作时,对于被复制对象,至少有一层是深复制. 完全复制(real-deep copy):在完全复制操作时,对于被复制对象的每一层都是对象复制. 两图以避之 理解深复制(mutableCopy) 浅复制很简单,就不演示了,看

Android系统进程间通信Binder机制在应用程序框架层的Java接口源代码分析_Android

        在前面几篇文章中,我们详细介绍了Android系统进程间通信机制Binder的原理,并且深入分析了系统提供的Binder运行库和驱动程序的源代码.细心的读者会发现,这几篇文章分析的Binder接口都是基于C/C++语言来实现的,但是我们在编写应用程序都是基于Java语言的,那么,我们如何使用Java语言来使用系统的Binder机制来进行进程间通信呢?这就是本文要介绍的Android系统应用程序框架层的用Java语言来实现的Binder接口了.        熟悉Android系统

深浅拷贝( 百度的)

深浅拷贝前提是:是实现NSCopying或者NSMutableCopying协议. 浅拷贝只是复制对象本身,对象的属性和包含的对象不做复制. 深拷贝则对对象本身复制,同是对对象的属性也进行复制. 深浅拷贝的本质区别是对象或者对象属性的内存地址是否一样,一样则为浅拷贝,不一样则为深拷贝. Foundation框架支持复制的类,默认是浅拷贝.其中对Foundation中不可变的对象进行copy时作用相当于retain. 而如果是mutablecopy时,无论对象是否可变,副本是可变的,并且实现了真正

【C/C++学院】0820-Nullptr/const对象/类指针引用以及mallocfree与newde/类重载运算符/QT加法重载/类的重载赋值运算/自增在前在后差别/赋值重载深浅拷贝/重载下标

Nullptr #include<iostream> void go(int num) { std::cout << "gonum" << std::endl; } void go(void *p) { std::cout << "gop" << std::endl; } void main() { //void *p = nullptr; void *p = NULL;//C++是强类型,严格的类型检查

Java开源运行分析工具(转)

  FProfiler  FProfiler是一个非常快的Java profiler.它利用BCEL和log4j来记录每个方法从开始到结尾的日记.FProfiler可以用来在你的应用程序,Servlet,Applet...中找出hotspots. 更多FProfiler信息   JRat  JRat是一个Java Runtime分析工具包.它的目的是让开发者更好的明白Java程序动行时的状态.JRat包括但并不只局限于性能剖析. 更多JRat信息   EJP  EJP(Extensible Ja

【C/C++学院】0819-/类的成员函数与const-mutable /构造与析构/拷贝构造deletedefault以及深浅拷贝/静态成员函数成员变量类在内存的存储默认参数/友元类以及友元函数

类的成员函数与const-mutable  成员函数 Fushu.h #pragma once #include <iostream> class fushu { public: int x; int y; public: fushu(); ~fushu(); void show(); inline void showall(int x, int y);//显式内联 void setxy(int x, int y);//编译器优化,默认隐式内联 void show(int x, int y);

从C C++的角度看PYTHON的深浅拷贝

原创如果有误请指出 今天看到python的列表深浅拷贝,不由得和C\C++进行了比较如下: 其实python中的深COPY和浅COPY和C\C++中是一样的,毕竟python底层是C/C++做的,这方面保留了 C\C++的原理,对于类或者结构体复制构造函数等号(=)操作符保留了浅COPY,当然我们可以自定义 这些函数.我们先从C++的简单的复制构造函数等号(=)操作符的例子开始 #include<iostream> #include <stdlib.h> #include <

Java源码分析:深入探讨Iterator模式

java.util包中包含了一系列重要的集合类.本文将从分析源码入手,深入研究一个集合类的内部结构,以及遍历集合的迭代模式的源码实现内幕. 下面我们先简单讨论一个根接口Collection,然后分析一个抽象类AbstractList和它的对应Iterator接口,并仔细研究迭代子模式的实现原理. 本文讨论的源代码版本是JDK 1.4.2,因为JDK 1.5在java.util中使用了很多泛型代码,为了简化问题,所以我们还是讨论1.4版本的代码. 集合类的根接口Collection Collect

android开发中的java内存泄露分析

做了较长时间的android开发了,发现其实android应用开发入门容易,但是进阶或者成为高级工程师,需要具备的基础能力还是非常高的:性能优化.内存泄露.apk瘦身.热修复等等,这些都非常的考验一个人的能力.android成长之路还很长,自己会持续的走下去.本文主要介绍android内存泄露方面的知识.其实要真的理解内存泄露,需要对JVM.java语言有一定的了解,在这个基础上就比较容易理解本文了. 一.内存泄露概念 在java中,如果一个对象没有可用价值了,但又被其他引用所指向,那么这个对象