简单对象的拷贝,直接使用其clone方法 即可, 不会有什么问题:

class Dog implements Cloneable 

public Dog clone() {

int age;
String name; // getter setter Dog myDog = null;
try {
  myDog = (Dog) super.clone();
} catch (CloneNotSupportedException e) {
  e.printStackTrace();
}
  return myDog;
} // any test ...

如此简单!

不过,如果对象有嵌套,我们还是使用这个做法(浅拷贝), 不注意就会出问题:

package design.creator.prototype;

import java.util.ArrayList;
import java.util.List; /**
* 浅拷贝:
*/
class Dog implements Cloneable {
int age;
String name;
List list;
Pojo pojo; public Dog(String tempName) {
name = tempName;
list = new ArrayList<>();
list.add();
list.add();
list.add();
pojo = new Pojo();
pojo.setV1();
pojo.setV2("aa");
} // public void ShowName() {
// System.out.println(name);
// } public Dog clone() {
Dog myDog = null;
try {
myDog = (Dog) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return myDog;
} public void setName(String name) {
this.name = name;
} public int getAge() {
return age;
} public void setAge(int age) {
this.age = age;
} public String getName() {
return name;
} public List getList() {
return list;
} public void setList(List list) {
this.list = list;
} @Override
public String toString() {
return "Dog [age=" + age + ", name=" + name +
", list=" + list + "]" + ", pojo=" + pojo + "]";
} public Pojo getPojo() {
return pojo;
} public void setPojo(Pojo pojo) {
pojo = pojo;
} } class Pojo {
int v1;
String v2;
public int getV1() {
return v1;
}
public void setV1(int v1) {
this.v1 = v1;
}
public String getV2() {
return v2;
}
public void setV2(String v2) {
this.v2 = v2;
}
@Override
public String toString() {
return "Pojo [v1=" + v1 + ", v2=" + v2 + "]";
} } public class PrototypeTest {
public static void main(String[] args) {
Dog myDog = new Dog("热狗");
myDog.setAge();
Dog newDog = (Dog) myDog.clone(); System.out.println(" myDog " + myDog );
System.out.println(" newDog " + newDog ); // myDog.ShowName();
// newDog.ShowName(); myDog.setName("aaaaa");
myDog.setAge();
myDog.getList().clear();
myDog.getPojo().setV1();
myDog.getPojo().setV2("bbb"); // myDog.ShowName();
// newDog.ShowName(); System.out.println(" myDog " + myDog );
System.out.println(" newDog " + newDog );
}
}

打印

 myDog Dog [age=, name=热狗, list=[, , ]], pojo=Pojo [v1=, v2=aa]]
newDog Dog [age=, name=热狗, list=[, , ]], pojo=Pojo [v1=, v2=aa]]
myDog Dog [age=, name=aaaaa, list=[]], pojo=Pojo [v1=, v2=bbb]]
newDog Dog [age=, name=热狗, list=[]], pojo=Pojo [v1=, v2=bbb]]

你可能不懂为什么newDog 的name没变化,而newDog 的pojo、list都发生了变化—— 原来java 的clone 方法把 String当做了普通字段并进行了深复制, 而其他对象类型数据仍然的浅复制。

那么正确的做法是:

package design.creator.prototype;

import java.util.ArrayList;
import java.util.List; /**
* 深度拷贝:
*/
class Dog implements Cloneable {
int age;
String name;
List list;
Pojo pojo; public Dog(String tempName) {
name = tempName;
list = new ArrayList<>();
list.add();
list.add();
list.add();
pojo = new Pojo();
pojo.setV1();
pojo.setV2("aa");
} public void setName(String name) {
this.name = name;
} public int getAge() {
return age;
} public void setAge(int age) {
this.age = age;
} public String getName() {
return name;
} public List getList() {
return list;
} public void setList(List list) {
this.list = list;
} @Override
public String toString() {
return "Dog [age=" + age + ", name=" + name +
", list=" + list + "]" + ", pojo=" + pojo + "]";
} public Pojo getPojo() {
return pojo;
} public void setPojo(Pojo pojo) {
pojo = pojo;
} public Dog clone() {
Dog myDog = null;
try {
myDog = (Dog) super.clone();
myDog.list = (List) ((ArrayList)myDog.list).clone(); // 想要调用其clone方法,必须1 implements Cloneable 2 对其重写clone
myDog.pojo = (Pojo) myDog.pojo.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return myDog;
}
} class Pojo implements Cloneable{
int v1;
String v2;
public int getV1() {
return v1;
}
public void setV1(int v1) {
this.v1 = v1;
}
public String getV2() {
return v2;
}
public void setV2(String v2) {
this.v2 = v2;
}
@Override
public String toString() {
return "Pojo [v1=" + v1 + ", v2=" + v2 + "]";
} @Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
} } public class PrototypeTest {
public static void main(String[] args) {
Dog myDog = new Dog("热狗");
myDog.setAge();
Dog newDog = (Dog) myDog.clone(); System.out.println(" myDog " + myDog );
System.out.println(" newDog " + newDog ); // myDog.ShowName();
// newDog.ShowName(); myDog.setName("aaaaa");
myDog.setAge();
myDog.getList().clear();
myDog.getPojo().setV1();
myDog.getPojo().setV2("bbb"); // myDog.ShowName();
// newDog.ShowName(); System.out.println(" myDog " + myDog );
System.out.println(" newDog " + newDog );
}
}

总结:

clone 方法只是浅拷贝,也就是说他只对象的第一层属性进行拷贝,其对象中的对象是不会进行重新拷贝的, 而仅仅只是拷贝那个引用。 如果对象有嵌套,那么需要注意重写相关步骤,使用 深拷贝。

参考:

http://blog.csdn.net/jariwsz/article/details/8588570

http://blog.csdn.net/xiaofengcanyuexj/article/details/23212189

再谈java clone 以及 浅/深拷贝的更多相关文章

  1. 沉淀再出发:再谈java的多线程机制

    沉淀再出发:再谈java的多线程机制 一.前言 自从我们学习了操作系统之后,对于其中的线程和进程就有了非常深刻的理解,但是,我们可能在C,C++语言之中尝试过这些机制,并且做过相应的实验,但是对于ja ...

  2. 再谈Java数据结构—分析底层实现与应用注意事项

    在回顾js数据结构,写<再谈js对象数据结构底层实现原理-object array map set>系列的时候,在来整理下java的数据结构. java把内存分两种:一种是栈内存,另一种是 ...

  3. Java clone克隆方法 --深拷贝--浅拷贝 --原型模型

    什么是深拷贝? 什么是浅拷贝? 创建一个对象的方法有几种? 默认的Object方法中的clone是深拷贝还是浅拷贝? 为什么说很多深拷贝都是不彻底的深拷贝? 什么是原型模型,什么是原型模式? 原型模型 ...

  4. 再谈java两种变量(基本类型和引用类型)(综合各路大神)

    基本类型: 基本类型自然不用说了,它的值就是一个数字,一个字符或一个布尔值. int  a:   a=250: //声明变量a的同时,系统给a分配了数据空间. 引用类型: 是一个对象类型,值是什么呢? ...

  5. 记一次synchronized锁字符串引发的坑兼再谈Java字符串

    问题描述 业务有一个需求,我把问题描述一下: 通过代理IP访问国外某网站N,每个IP对应一个固定的网站N的COOKIE,COOKIE有失效时间.并发下,取IP是有一定策略的,取到IP之后拿IP对应的C ...

  6. 记一次 synchronized 锁字符串引发的坑兼再谈 Java 字符串

    业务有一个需求,我把问题描述一下: 通过代理IP访问国外某网站N,每个IP对应一个固定的网站N的COOKIE,COOKIE有失效时间. 并发下,取IP是有一定策略的,取到IP之后拿IP对应的COOKI ...

  7. Java知多少(25)再谈Java包

    在Java中,为了组织代码的方便,可以将功能相似的类放到一个文件夹内,这个文件夹,就叫做包. 包不但可以包含类,还可以包含接口和其他的包. 目录以"\"来表示层级关系,例如 E:\ ...

  8. [Java学习] 再谈Java包

    在Java中,为了组织代码的方便,可以将功能相似的类放到一个文件夹内,这个文件夹,就叫做包. 包不但可以包含类,还可以包含接口和其他的包. 目录以"\"来表示层级关系,例如 E:\ ...

  9. 三. Java类与对象8.再谈Java包

    在Java中,为了组织代码的方便,可以将功能相似的类放到一个文件夹内,这个文件夹,就叫做包. 包不但可以包含类,还可以包含接口和其他的包. 目录以"\"来表示层级关系,例如 E:\ ...

随机推荐

  1. sql Find_IN_SET 用法

    字段以 1,2,3,4 格式存储的SELECT * from test where FIND_IN_SET('15',btype) GROUP_CONCAT + group_by

  2. 为IE内核的WebBrowser控件内存泄漏所烦恼的可以考虑用Cefsharp代替它!

    为IE内核的WebBrowser控件内存泄漏所烦恼的朋友们,可以考虑用Cefsharp代替WebBrowser控件 特意做了一个程序来测试 利用Cefsharp做控件,访问网站.每分钟刷新2次,初始时 ...

  3. 模拟a标签click,弹出新页面

    $("<a>").attr("href", url).attr("target", "_blank")[0] ...

  4. Hadoop错误集:Journal Storage Directory not formatted

    类型一: 当你从异常信息中看到JournalNode not formatted,如果在异常中看到三个节点都提示需要格式化JournalNode. 如果你是新建集群,你可以重新格式化NameNode, ...

  5. react基础

    上一篇文章主要是记录了自己是如何创建react项目的,今天则主要是总结一下react中的一个基础入门知识,包括数据定义和绑定.属性绑定.数组循环等等. 组件继承和挂载 当我们使用脚手架或者命令行创建一 ...

  6. 跨域的案例 以百度接口/手写接口为例,还有jQuery写法

    仅在js部分输入即可 百度接口的案例 <script> function fn(data){ console.log(data) } </script> <script ...

  7. HDOJ 2001 计算两点间的距离

    #include<iostream> #include<cstdio> using namespace std; int main() { double a, b, x, y; ...

  8. [UE4]读取玩家列表

  9. webpack、npm、nginx常用命令

    webpack命令:webpack --watch 监听变动并自动打包,简写-wwebpack -p --progress --color 压缩混淆脚本webpack -d  生成映射文件,告知那些模 ...

  10. python容器数据类型的特色

    python容器数据类型的特色 list:           可变数据类型(不可哈希), 有序, 可索引获取, 可修改 Dict:         可变数据类型(不可哈希), 3.6版本有序, 可通 ...