Java中的深克隆和浅克隆——Cloneable接口

本文涉及的产品
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
简介:

一、没有使用克隆带来的问题

public class CloneTest

{

static Student s = new Student("aaa", 20);


// 直接赋值带来的问题

public static void noclone()

{

// 传的是引用的副本,改变了noCloneStudent也改变了s

Student noCloneStudent = new Student();

noCloneStudent = s;

noCloneStudent.setName("bbb");

noCloneStudent.setAge(21);

System.out.println(s);

System.out.print(noCloneStudent);

}

}

Student [name=bbb, age=21]

Student [name=bbb, age=21]

本意是设置noCloneStudent中的值,但把原来的对象s中的值也改变了。


二、浅克隆与深克隆

①浅克隆——若要克隆Student对象,只克隆他自身以及他包含的所有对象的引用地址。

②深克隆——克隆除自身以外所有的对象,包括自身所包含的所有对象实例。由具体的需求决定深克隆的层次(N层克隆)。


三、浅克隆

public class Student implements Cloneable

{

private String name;

private int age;


public Student()

{

super();

}


public Student(String name, int age)

{

super();

this.name = name;

this.age = age;

}



// 浅克隆

protected Object clone() throws CloneNotSupportedException

{

return super.clone();

}


public String toString()

{

return "Student [name=" + name + ", age=" + age + "]";

}

......

}


public class CloneTest

{

static Student s = new Student("aaa", 20);

// 浅克隆

public static void test0() throws Exception

{

Student ss = (Student) s.clone();

ss.setName("bbb");

ss.setAge(21);

System.out.println(s);

System.out.print(ss);

}

}

Student [name=aaa, age=20]

Student [name=bbb, age=21]

克隆的效果就达到了。


四、深克隆

public class TClass implements Cloneable

{

private Student stu;

private String name;

private List<String> courses = new ArrayList<String>();


public TClass()

{

super();

}


public TClass(Student stu, String name, List<String> courses)

{

super();

this.stu = stu;

this.name = name;

this.courses = courses;

}


// 深克隆

public Object clone() throws CloneNotSupportedException

{

TClass tea = (TClass) super.clone();

tea.stu = (Student) tea.stu.clone();

return tea;

}


public String toString()

{

return "TClass [stu=" + stu + ", name=" + name + ", courses=" + courses + "]";

}

......

}

// 深克隆

public static void test1() throws Exception

{

TClass t = new TClass();

t.setStu(s);

t.setName("张老师");

t.getCourses().add("JAVA");

t.getCourses().add("C#");

System.out.println(t);

TClass tt = (TClass) t.clone();

Student sss = (Student) s.clone();

sss.setName("bbb");

sss.setAge(21);

tt.setStu(sss);

tt.setName("李老师");

tt.getCourses().add("oracle");

tt.getCourses().add("mysql");

System.out.println(t);

System.out.println(tt);

}

TClass [stu=Student [name=aaa, age=20], name=张老师, courses=[JAVA, C#]]

TClass [stu=Student [name=aaa, age=20], name=张老师, courses=[JAVA, C#, oracle, mysql]]

TClass [stu=Student [name=bbb, age=21], name=李老师, courses=[JAVA, C#, oracle, mysql]]

动态数组还是保留了原来的引用,所以其数组没有达到拷贝的效果。


改造一下,让其中的数组有新的引用

public class TClass implements Cloneable

{

private Student stu;

private String name;

private List<String> courses = new ArrayList<String>();


public TClass()

{

super();

}


public TClass(Student stu, String name, List<String> courses)

{

super();

this.stu = stu;

this.name = name;

this.courses = courses;

}


// 深克隆(更深一层)

public Object clone() throws CloneNotSupportedException

{

TClass tea = (TClass) super.clone();

tea.stu = (Student) tea.stu.clone();

tea.courses = new ArrayList<String>(); // 指向不同引用

return tea;

}


public String toString()

{

return "TClass [stu=" + stu + ", name=" + name + ", courses=" + courses + "]";

}

......

}

TClass[stu=Student [name=aaa, age=20], name=张老师, courses=[Java, C#]]

TClass[stu=Student [name=bbb, age=21], name=李老师, courses=[oracle, mysql]]


再改造一下,希望动态数组既有了新的引用,又保留了原值

public class TClass3 implements Cloneable

{

private Student stu;

private String name;

private List<String> courses = new ArrayList<String>();


public TClass()

{

super();

}


public TClass(Student stu, String name, List<String> courses)

{

super();

this.stu = stu;

this.name = name;

this.courses = courses;

}


// 深克隆(更深一层)

public Object clone() throws CloneNotSupportedException

{

TClass tea = (TClass) super.clone();

tea.stu = (Student) tea.stu.clone();

// 指向不同引用

tea.courses = new ArrayList<String>();

// 又想保留原有的值

for (int i = 0; i < courses.size(); i++)

{

tea.courses.add(courses.get(i));

}

return tea;

}


public String toString()

{

return "TClass [stu=" + stu + ", name=" + name + ", courses=" + courses + "]";

}

......

}

Teacher [stu=Student [name=aaa, age=20], name=张老师, courses=[Java, C#]]

Teacher [stu=Student [name=bbb, age=21], name=李老师, courses=[Java, C#, oracle, spring]]

本文转自IT徐胖子的专栏博客51CTO博客,原文链接http://blog.51cto.com/woshixy/1409503如需转载请自行联系原作者

woshixuye111
相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
1月前
|
Java
【Java】一个简单的接口例子(帮助理解接口+多态)
【Java】一个简单的接口例子(帮助理解接口+多态)
17 0
C4.
|
1月前
|
Java
Java的接口
Java的接口
C4.
21 0
|
1月前
|
Java
JAVA接口
JAVA接口
12 0
|
5天前
|
Java 开发者
探索 Java 的函数式接口和 Lambda 表达式
【4月更文挑战第19天】Java 中的函数式接口和 Lambda 表达式提供了简洁、灵活的编程方式。函数式接口有且仅有一个抽象方法,用于与 Lambda(一种匿名函数语法)配合,简化代码并增强可读性。Lambda 表达式的优点在于其简洁性和灵活性,常用于事件处理、过滤和排序等场景。使用时注意兼容性和变量作用域,它们能提高代码效率和可维护性。
|
6天前
|
Java
Java接口中可以定义哪些方法?
【4月更文挑战第13天】
9 0
Java接口中可以定义哪些方法?
|
8天前
|
设计模式 Java
Java接口与抽象类
Java接口与抽象类
17 0
|
12天前
|
安全 Java 编译器
接口之美,内部之妙:深入解析Java的接口与内部类
接口之美,内部之妙:深入解析Java的接口与内部类
34 0
接口之美,内部之妙:深入解析Java的接口与内部类
|
14天前
|
存储 Java
java接口和内部类
java接口和内部类
|
16天前
|
缓存 安全 Java
Java中函数式接口详解
Java 8引入函数式接口,支持函数式编程。这些接口有单一抽象方法,可与Lambda表达式结合,简化代码。常见函数式接口包括:`Function&lt;T, R&gt;`用于转换操作,`Predicate&lt;T&gt;`用于布尔判断,`Consumer&lt;T&gt;`用于消费输入,`Supplier&lt;T&gt;`用于无参生成结果。开发者也可自定义函数式接口。Lambda表达式使实现接口更简洁。注意异常处理和线程安全。函数式接口广泛应用于集合操作、并行编程和事件处理。提升代码可读性和效率,是现代Java开发的重要工具。
29 0
|
16天前
|
Java 关系型数据库 MySQL
大厂面试题详解:Java抽象类与接口的概念及区别
字节跳动大厂面试题详解:Java抽象类与接口的概念及区别
40 0