什么是"clone"?

  在实际编程过程中,我们常常要遇到这种情况:有一个对象A,在某一时刻A中已经包含了一些有效值,此时可能 会需要一个和A完全相同新对象B,并且此后对B任何改动都不会影响到A中的值,也就是说,A与B是两个独立的对象,但B的初始值是由A对象确定的。在 Java语言中,用简单的赋值语句是不能满足这种需求的。要满足这种需求虽然有很多途径,但实现clone()方法是其中最简单,也是最高效的手段。

   Java的所有类都默认继承java.lang.Object类,在java.lang.Object类中有一个方法clone()。JDK API的说明文档解释这个方法将返回Object对象的一个拷贝。要说明的有两点:一是拷贝对象返回的是一个新对象,而不是一个引用。二是拷贝对象与用 new操作符返回的新对象的区别就是这个拷贝已经包含了一些原来对象的信息,而不是对象的初始信息。

如何使用clone方法

首先需要实现CloseAble类

 @Override
public Object clone() throws CloneNotSupportedException {
Student s = null;
try {
s = (Student) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return s;
}

浅复制:

1、创建类Student

 public class Student implements  Cloneable {

     private String name;
private int age;
private Professor professor; public Student(String name, int age, Professor professor) {
this.name = name;
this.age = age;
this.professor = professor;
} 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 Professor getProfessor() {
return professor;
} public void setProfessor(Professor professor) {
this.professor = professor;
} @Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", professor=" + professor +
'}';
} @Override
public Object clone() throws CloneNotSupportedException {
Student s = null;
try {
s = (Student) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return s;
}
}

2、创建类Professor

 public class Professor{
private String name;
private int age; public Professor(String name, int age) {
this.name = name;
this.age = age;
} 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;
} @Override
public String toString() {
return "Professor{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}

3、执行

  @Test
public void cloneT(){
Professor p1 = new Professor("Professor Zhang",30); Student s1 = new Student("xiao ming",18,p1); System.out.println(s1); try {
Student s2 = (Student) s1.clone();
s2.setName("xiao hong");
s2.setAge(17);
Professor p2 = s2.getProfessor();
p2.setName("Professor Li");
p2.setAge(45);
s2.setProfessor(p2);
System.out.println("复制后的:s1 = " + s1);
System.out.println("复制后的:s2 = " + s2);
} catch (CloneNotSupportedException e) {
e.printStackTrace();
} }

4、运行结果:

1 Student [name=xiao ming, age=18, professor=Professor [name=Professor Zhang, age=30]]
2 复制后的:s1 = Student [name=xiao ming, age=18, professor=Professor [name=Professor Li, age=45]]
3 复制后的:s2 = Student [name=xiao hong, age=17, professor=Professor [name=Professor Li, age=45]]

问题:发现修改s2的Professor,对应的s1也变了,但是基本类型 name和age没有跟着改变。这主要是浅复制带来的问题,若要解决这个问题,需要使用深复制。

深复制:

1、为Professor 类添加clone方法

  @Override
public Object clone() throws CloneNotSupportedException {
Professor p = null;
try {
p = (Professor) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return p;
}

2、修改Student的clone方法

  @Override
public Object clone() throws CloneNotSupportedException {
Student s = null;
try {
s = (Student) super.clone();
s.professor = (Professor) this.professor.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return s;
}

提示: 对于上面的解决方案还是存在一个问题,若我们系统中存在大量的对象是通过拷贝生成的,如果我们每一个类都写一个clone()方法,并将还需要进行深拷贝,新建大量的对象,这个工程是非常大的,这里我们可以利用序列化来实现对象的拷贝。

 public class CloneUtils {
@SuppressWarnings("unchecked")
public static <T extends Serializable> T clone(T obj){
T cloneObj = null;
try {
//写入字节流
ByteArrayOutputStream out = new ByteArrayOutputStream();
ObjectOutputStream obs = new ObjectOutputStream(out);
obs.writeObject(obj);
obs.close(); //分配内存,写入原始对象,生成新对象
ByteArrayInputStream ios = new ByteArrayInputStream(out.toByteArray());
ObjectInputStream ois = new ObjectInputStream(ios);
//返回生成的新对象
cloneObj = (T) ois.readObject();
ois.close();
} catch (Exception e) {
e.printStackTrace();
}
return cloneObj;
}
}

使用该工具类的对象必须要实现Serializable接口,否则是没有办法实现克隆的。

 public class Person implements Serializable{
private static final long serialVersionUID = 2631590509760908280L; ..................
//去除clone()方法 } public class Email implements Serializable{
private static final long serialVersionUID = 1267293988171991494L; ....................
}

所以使用该工具类的对象只要实现Serializable接口就可实现对象的克隆,无须继承Cloneable接口实现clone()方法。

3、输出结果

1 Student [name=xiao ming, age=18, professor=Professor [name=Professor Zhang, age=30]]
2 复制后的:s1 = Student [name=xiao ming, age=18, professor=Professor [name=Professor Zhang, age=30]]
3 复制后的:s2 = Student [name=xiao hong, age=17, professor=Professor [name=Professor Li, age=45]]

注意:final 类型修饰的成员变量不能进行深度拷贝

参考地址:https://www.cnblogs.com/acode/p/6306887.html

java的clone()方法的更多相关文章

  1. Java基础——clone()方法浅析

    一.clone的概念 clone顾名思义就是复制, 在Java语言中, clone方法被对象调用,所以会复制对象.所谓的复制对象,首先要分配一个和源对象同样大小的空间,在这个空间中创建一个新的对象.那 ...

  2. Java的clone方法效率问题

    在Java中,经常会需要新建一个对象,很多情况下,需要这个新建的对象和现有的某个对象保持属性一致. 那么,就有两种方式来实现这个对象的构造: ①通过新建一个对象,为这个对象的属性根据原有对象的属性来进 ...

  3. 分析java中clone()方法 (转载+修改)

    Java中的clone() 方法 java所有的类都是从java.lang.Object类继承而来的,而Object类提供下面的方法对对象进行复制. protected native Object c ...

  4. Java中clone方法的使用

    什么是clone 在实际编程过程中,我们常常要遇到这种情况:有一个对象object1,在某一时刻object1中已经包含了一些有效值,此时可能会需要一个和object1完全相同新对象object2,并 ...

  5. Java 的 clone 方法 && 浅复制和深复制

    1 Java中对象的创建过程 java创建对象的方式有以下两种: (1)使用new操作符创建一个对象 (2)使用clone的方法复制一个对象,(在Java中,clone是Object类的protect ...

  6. Java的clone方法

    现在有User类:(Getter和Setter省略) public class User implements Cloneable { private String name; private int ...

  7. java的 clone方法

    1.java语言中没有明确提供指针的概念与用法,而实质上每个new语句返回的都是一个指针的引用,只不过在大部分情况下开发人员不需要关心如果取操作这个指针而已. 2.在java中处理基本数据类型时,都是 ...

  8. 详解Java中的clone方法

    详解Java中的clone方法 参考:http://blog.csdn.net/zhangjg_blog/article/details/18369201/ 所谓的复制对象,首先要分配一个和源对象同样 ...

  9. Object类clone方法的自我理解

    网上搜帖: clone()是java.lang.Object类的protected方法,实现clone方法: 1)类自身需要实现Cloneable接口 2)需重写clone()方法,最好设置修饰符mo ...

随机推荐

  1. 如何利用HTTP缓存来加快你的网站应用

    缓存在web环境各个环节都有实现,有CPU缓存.文件缓存.程序的Opcode缓存(APC,eAccelerator).内存缓存(Memcached,Redis).代理服务器(Nginx,Squid). ...

  2. Python:黑板课爬虫闯关第一关

    近日发现了[黑板课爬虫闯关]这个神奇的网页,练手爬虫非常的合适 地址:http://www.heibanke.com/lesson/crawler_ex00/ 第一关非常的简单 get 请求网址,在响 ...

  3. 兼容小程序的canvas画图组件jmGraph

    基于CANVAS的简单画图组件让你用类似于dom的方式,在canvas上画图,感觉会不会很爽. 主页:http://graph.jm47.com/示例:http://graph.jm47.com/ex ...

  4. 远程连接桌面报:这可能是由于credssp加密oracle修正

      1.Win+R 输入regedit打开注册表 找到对应的以下目录HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Polic ...

  5. 解决Windows对JDK默认版本切换问题

    注意修改path路径,或者修改控制面板下的java控制面板并不有效,原因是由于在WINDOWS\System32环境变量中的优先级高于JAVA_HOME设置的环境变量优先级,故如果只修改环境变量JAV ...

  6. oracle学习笔记(二) 基本数据类型

    常用的数据类型 int number number(4,1) 999.1 四个数字,小数位一位 decimal date 日期 格式如下: 注意:日期类型的字段格式,可以通过以下三种方式: 1. da ...

  7. @Data注解使用后在eclipse中get/set报错解决方法

    Maven项目中已经导入相关的lombok.jar包但是使用后仍提示无set/get方法 安装完成之后,请确认eclipse安装路径下是否多了一个lombok.jar包,并且其 配置文件eclipse ...

  8. 微信小程序推广技巧、营销方案

    小程序已经成功上线了!那么,小程序线下如何推广?线下门店如何玩转小程序呢? 1.附近的小程序,让商家曝光率更高 小 程序自带“附近的小程序”功能,利用LBS定位功能提高商家专属微信小程序的曝光度,用户 ...

  9. MongoDB个人简单总结

    当同一个变量被连续插入两次会出现id相同的异常,但是同样内容的两个变量同时插入不会有问题,可能是同一个变量同一个地址生成id相同,导致异常. 默认登陆不需要用户名密码认证,需要密码认证登陆需要在adm ...

  10. C# Base64方式的编码与解码

    编码与解码方法: ///编码 public static string EncodeBase64(string code_type, string code) { string encode = &q ...