我们都知道,java提供了Cloneable接口,其意思就是对象的拷贝,我们用到这功能的时候,需实现这个接口!

那我们为什么要用它?用它能给我们带来什么好处呢?

因为拷贝是在内存中进行的,所以,比直接new对象要快,特别是在大对象的生存上(有别于数据库中的clob,特指属性比较多,字段比较复杂的对象),但是对象的拷贝也会带给我们一些迷惑,稍有不慎便会陷入这个坑中。

列子1:

public class TestClone {
public static void main(String[] args) {
Person father=new Person("父亲");
Person subPer=new Person("儿子",father);
//儿子二是通过subPer拷贝过来的
Person subPer1=subPer.clone();
subPer1.setName("儿子1");
System.out.println(subPer.getName()+"的父亲是"+subPer.getFather().getName());
System.out.println(subPer1.getName()+"的父亲是"+subPer.getFather().getName());

}

}

public class Person implements Cloneable {
//姓名
private String name="";
//父亲
   private Person father=null;
   public Person(String name){
    this.name=name;
   }
   public Person(String name,Person father){
    this.name=name;
    this.father=father;
   }
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Person getFather() {
return father;
}
public void setFather(Person father) {
this.father = father;
}
@Override
protected Person clone() {
Person p=null;
try{
p=(Person) super.clone();
}catch(CloneNotSupportedException e){
e.printStackTrace();
}

return p;
}

}

这里模拟了一个父亲有两个儿子这么一个场景,大儿子和小儿子同种,所以小儿子的对象是通过拷贝大儿子的对象来完成的,这十分正确,没什么问题的啊!但是呢?软件的开发修改时无穷尽的,就比如有那么一天,老爸突然心血来潮,突然想给大儿子找个干爹


Person father=new Person("父亲");
Person subPer=new Person("儿子",father);
//儿子1二是通过儿子拷贝过来的
Person subPer1=subPer.clone();
subPer1.setName("儿子1");
subPer.getFather().setName("大儿子的个干爹");
System.out.println(subPer.getName()+"的父亲是"+subPer.getFather().getName());
System.out.println(subPer1.getName()+"的父亲是"+subPer.getFather().getName());

其结果是 

Person father=new Person("父亲");
Person subPer=new Person("儿子",father);
//儿子1二是通过儿子拷贝过来的
Person subPer1=subPer.clone();
subPer1.setName("儿子1");
subPer.getFather().setName("大儿子的个干爹");
System.out.println(subPer.getName()+"的父亲是"+subPer.getFather().getName());
System.out.println(subPer1.getName()+"的父亲是"+subPer.getFather().getName());


其结果是:

儿子的父亲是大儿子的个干爹
儿子1的父亲是大儿子的个干爹

两儿子的老爸都变了,这个老爹从人间蒸发,妈妈啊!

出现这种现象的原因是什么呢?

我们都知道,java中所有的类都继承Object,Object提供了一个默认的拷贝方法,即super.clone(),但是,该方法是有缺陷的,它提供的是一种浅拷贝,它不把对象的所有属性都拷贝一份,它支持基本数据类型 比如int,float,double,如果变量是一个实例对象,则拷贝地址引用,也就是说此时新拷贝出来的对象与原有的对象共享该实例变量,不受访问权限的限制。我的妈妈啊!这不是违背了java 中private 只能在一个类中使用的原则么,这让java 的private 情何以堪!!!!

 也许你也发现了,String不也是引用类型的么?不也是能正常拷贝么,呵呵,这就得说说String 这个玩意,这个玩意比较特殊,特殊在什么地方呢?其实clone 的时候也是拷贝的地址,但是呢,修改的时候会从字符串池中重新生成新的字符串,原有的字符串保存不变,其实这么一说也就明白了 原来儿子一是通过大儿子产生的,我的乖乖!!那怎么修改呢?


protected Person clone() {
Person p=null;
try{
p=(Person) super.clone();
p.setFather(new Person(p.getFather().getName()));
}catch(CloneNotSupportedException e){
e.printStackTrace();
}

return p;
}

这就是对引用类型的拷贝,聪明的你或许已经发现,其实对引用的拷贝是在什么地方修改的,那我们来看看集合的拷贝!

列2:对集合的拷贝

public class Person implements Cloneable{
// 姓名
private String name;
// 年龄
private int age;
// 性别
private String sex;
//朋友
private List<String> friends;

public List<String> getFriends() {
return friends;
}

public void setFriends(List<String> friends) {
this.friends = friends;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public int getAge() {
return age;
}

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

public String getSex() {
return sex;
}

public void setSex(String sex) {
this.sex = sex;
}

public Person clone() {
try {
Person person  = (Person)super.clone();
List<String> newfriends = new ArrayList<String>();
for(String friend : this.getFriends()) {
newfriends.add(friend);
}
person.setFriends(newfriends);
return  person;
} catch (CloneNotSupportedException e) {
e.printStackTrace();
return null;
}
}

}


ok,我们已经知道了拷贝的使用,但是呢?你想过没,如果项目中有大量的对象是通过拷贝来生存的,那我们该如何处理呢?一种选择方式是通过序列化方式来处理,何为序列化?就是对象可以通过介质传输,列如内存,然后通过反序列化可以得到原始的对象,


public class CloneUtils {
public CloneUtils() {
throw new Error("工具类不能创建对象!");
}

@SuppressWarnings("unchecked")
public static <T extends Serializable> T clone(T obj) {
// T 拷贝产生的对象
T cloneObj = null;
try {
// 读取对象字节流
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(obj);
oos.close();
// 分配内存空间,写入原始对象,生存新对象
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
cloneObj = (T) ois.readObject();
ois.close();
} catch (Exception e) {
}
return cloneObj;
}
}


java的clone你知道多少?相关推荐

  1. Java克隆(Clone)的应用

    Java克隆(Clone)的应用 简介: Java克隆(Clone)是Java语言的特性之一,但在实际中应用比较少见.但有时候用克隆会更方便更有效率. 对于克隆(Clone),Java有一些限制: 1 ...

  2. Java设计模式百例(番外) - Java的clone

    本文源码见:https://github.com/get-set/get-designpatterns/tree/master/prototype 本文是为下一篇"Java设计模式百例 - ...

  3. java deep clone util_Java Clone深拷贝与浅拷贝的两种实现方法

    1.首先,你要知道怎么实现克隆:实现Cloneable接口,在bean里面重写clone()方法,权限为public. 2.其次,你要大概知道什么是地址传递,什么是值传递. 3.最后,你要知道你为什么 ...

  4. java中clone方法_Java Object clone()方法– Java中的克隆

    java中clone方法 Cloning is the process of creating a copy of an Object. Java Object class comes with na ...

  5. Java的Clone

    Clone 就是重写clone()方法 两种办法进行深拷贝,一种是Clonable接口,一种是Serializable接口 实现代码如下 package Clone;public class Stud ...

  6. java深度克隆_浅析Java中clone()方法浅克隆与深度克隆

    现在Clone已经不是一个新鲜词语了,伴随着"多莉"的产生这个词语确实很"火"过一阵子,在Java中也有这么一个概念,它可以让我们很方便的"制造&qu ...

  7. Java的clone()用法实例解析

    1.背景 用java写程序的时候很苦恼的一件事就是,如果将一个对象a赋给另一个对象b,那么你改变a的变量值得时候,b的值也对应的变化.如果我们只想单纯的获取那个时刻的a的状况给b的话,就要用到clon ...

  8. 浅析java中clone()方法

    本文转载自:http://blog.csdn.net/mengxiangyue/article/details/6818611 Java中我们可能都遇到过这样的情况,在我们将一个对象做为参数传给一个函 ...

  9. java super.clone解释_super.clone()做了什么

    java对象如果想被克隆,它对应的类需要implements标志接口Cloneable.如果不重写clone()方法,则在调用clone()方法实现的是浅复制(所有的引用对象保持不变,意思是如果原型里 ...

最新文章

  1. python batch normalization_Batch Normalization 引出的一系列问题
  2. python扫雷代码_室友扫雷通关来炫耀!我用Python做出自动扫雷十秒通关!
  3. 使用EHPC实现“完美并行”的高效批处理方案
  4. Hadoop供应商MapR:先上市, “不久之后”就会盈利
  5. 笔记-信息系统安全管理-安全审计
  6. UOJ #149 [NOIP 2015] 子串
  7. Qt QGraphics体系及刷新机制介绍
  8. subversion安装与配置备忘录
  9. CIO启示:转向数字业务为传统IT带来颠覆性影响
  10. python123电脑登录不了_python(14)- 简单练习:登录账户失败三次,账户自动锁定...
  11. 前端全栈必会node框架koa。。。
  12. java swing有趣编程_java(swing编程)如何这个简单效果?
  13. php 轮播代码生成器,阿里巴巴国际站全屏轮播代码生成器 阿里国际站全屏轮播切换代码阿里巴巴全屏轮播怎么做? 一秒钟美工助手官方网站...
  14. 移植STM32F103VE程序到STM32F207VE系列应用注意事项
  15. java mis_关于使用java开发Mis系统的相关内容。
  16. LED恒流驱动IC汇总
  17. 2015年河南省省赛部分题题解
  18. osm数据下载 python_Python环境下使用OpenStreetMap下载的.osm数据
  19. Dreamweaver CS6安装及破解步骤
  20. 小孩手工_儿童折纸大全_近150篇儿童手工折纸图解教程,小孩折纸必备 - 聚巧网...

热门文章

  1. 双臂机器人驱动板(LM324运放电流检测、PCF8591外置ADC)
  2. 关于使用google map实现周边搜索的功能
  3. JAVA洛谷B2117 整理药名
  4. 中兴网关(光猫)DNS故障的解决
  5. Linux驱动 | 加载.ko驱动模块的两种方法(insmod与modprobe)
  6. IDEA(2018.2)的下载、安装及破解
  7. L1正则化与L2正则化详解
  8. 如何在手机上阅读caj格式论文
  9. wormhole make 问题
  10. DOC与DOCX的区别