Java克隆clone的浅复制与深复制
来源:互联网 发布:alex卞正伟淘宝店 编辑:程序博客网 时间:2024/05/07 14:37
一、需求
1.问题引入:
假设在你的应用中想修改某个对象的属性或值,比如:我想修改某个ArrayList 集合对象list存有的元素,但我又不想影响原来的集合对象list,那么该怎么做呢?
或许你会想到直接这样 ArrayList list2 = list; 不就行了吗?呵呵,其实这样不是拷贝,这样的话list2 就完全等于list,操作list2即是操作list。
换换言之,在你执行这个操作后仍然只有一个对象,你只是多加了一个该list对象的一个引用。那么该如何解决这个问题呢?
2.解决方案:
使用所有类的父类Object 的clone()方法。
3.测试用例:
package org.xjh.test;import java.util.ArrayList;/** * ArrayList的clone方法测试 * @author xjh * */public class CloneTest {public static void main(String[] args) {ArrayList list = new ArrayList();list.add("123");list.add(1);list.add(100.0);System.out.println("初始list集合中的所有元素:" + list);ArrayList list2 = list;list2.remove(0);System.out.println("移除list2集合第一个元素之后,list集合的所有元素:" +list);ArrayList list3 = (ArrayList) list.clone();list3.remove(0);System.out.println("移除list3集合第一个元素之后,list集合的所有元素:" + list);}}
初始list集合中的所有元素:[123, 1, 100.0]
移除list2集合第一个元素之后,list集合的所有元素:[1, 100.0]
移除list3集合第一个元素之后,list集合的所有元素:[1, 100.0]
二、自定义可克隆的类(浅复制)
1.定义
浅拷贝(浅复制、浅克隆):被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。换言之,浅拷贝仅仅复制所考虑的对象,而不复制它所引用的对象。
2.实现步骤:
1).在自定义类中覆盖Object类的clone()方法,并声明为public(Object类中的clone()方法是protected的,在子类重写的时候,可以扩大访问修饰符的范围)。
2).在自定义类的clone()方法中,调用super.clone()。
因为在运行时刻,Object类中的clone()识别出你要复制的是哪一个对象,然后为此对象分配空间,并进行对象的复制,将原始对象的内容一一复制到新对象的存储空间中。
3).在派生类中实现Cloneable接口。Cloneable接口中没有任何方法,只是作一种声明,表示该类具有复制的作用。
2.测试用例:
package org.xjh.test;import java.util.ArrayList;/** * 浅复制测试 * @author xjh * */public class CloneTest {public static void main(String[] args) throws CloneNotSupportedException {Student s1 = new Student("张三", 12);Student s2 = (Student) s1.clone();Student s3 = s1;System.out.println("s1的初始age的值="+s1.getAge());s2.setAge(20);System.out.println("修改s2的age值="+s2.getAge());System.out.println("修改s2的age值后,s1的age的值="+s1.getAge());s3.setAge(30);System.out.println("修改s3的age值="+s3.getAge());System.out.println("修改s2的age值后,s1的age的值="+s1.getAge());}}/** * 实现Cloneable接口并且覆写Object的clone方法的Student类 * @author xjh * */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;}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; } /** * 覆写Object类的clone方法,注意此处要把protected改为public,不然没法调用 */ @Override public Object clone() throws CloneNotSupportedException { return super.clone(); }}
3.测试结果:
s1的初始age的值=12
修改s2的age值=20
修改s2的age值后,s1的age的值=12
修改s3的age值=30
修改s2的age值后,s1的age的值=30
三、自定义可复制的类(深复制)
1.定义
深拷贝(深复制、深克隆):被复制对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量。
那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象。
换言之,深拷贝把要复制的对象所引用的对象都复制了一遍。
2.实现步骤
前提假设,A类中定义了一个属性,这个属性是另外一个类B的引用对象b。
1).在自定义类中覆盖Object类的clone()方法,并声明为public(Object类中的clone()方法是protected的,在子类重写的时候,可以扩大访问修饰符的范围)。
2).在自定义类的clone()方法中,调用super.clone()。
因为在运行时刻,Object类中的clone()识别出你要复制的是哪一个对象,然后为此对象分配空间,并进行对象的复制,将原始对象的内容一一复制到新对象的存储空间中。
3).在派生类中实现Cloneable接口。Cloneable接口中没有任何方法,只是作一种声明,表示该类具有复制的作用。
4).在A类的clone方法中调用B类引用对象b的clone方法,并且让b重新指向b.clone的对象
3. 测试用例
package org.xjh.test;/** * 深复制测试 * @author xjh * */public class CloneTest2{ public static void main(String[] args) throws Exception { Teacher teacher = new Teacher(); teacher.setName("Teacher Zhang"); teacher.setAge(40); Student2 student1 = new Student2(); student1.setName("ZhangSan"); student1.setAge(20); student1.setTeacher(teacher); Student2 student2 = (Student2) student1.clone(); System.out.println("拷贝得到的信息"); System.out.println(student2.getName()); System.out.println(student2.getAge()); System.out.println(student2.getTeacher().getName()); System.out.println(student2.getTeacher().getAge()); System.out.println("-------------"); // 修改老师的信息 teacher.setName("Teacher Zhang has changed"); System.out.println(student1.getTeacher().getName()); System.out.println(student2.getTeacher().getName()); // 两个引用student1和student2指向不同的两个对象 // 但是两个引用student1和student2中的两个teacher引用指向的是同一个对象 // 所以说明是浅拷贝 // 改为深复制之后,对teacher对象的修改只能影响第一个对象 }}class Teacher implements Cloneable{ private String name; private int 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 Object clone() throws CloneNotSupportedException { return super.clone(); }}class Student2 implements Cloneable{ private String name; private int age; private Teacher teacher; 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 Teacher getTeacher() { return teacher; } public void setTeacher(Teacher teacher) { this.teacher = teacher; } @Override public Object clone() throws CloneNotSupportedException { // 浅复制时: // Object object = super.clone(); // return object; // 改为深复制: Student2 student = (Student2) super.clone(); // 本来是浅复制,现在将Teacher对象复制一份并重新set进来 student.setTeacher((Teacher) student.getTeacher().clone()); //当然,也可以这样做,效果与上面的一样 //this.teacher = (Teacher) student.getTeacher().clone(); return student; }}
3.测试结果:
拷贝得到的信息
ZhangSan
20
Teacher Zhang
40
-------------
Teacher Zhang
Teacher Zhang has changed
四、应用场景
那么,什么时候需要进行对象的克隆呢,一般需要满足以下条件:
1. 克隆对象与原对象不是同一个对象。即对任何的对象x:
x.clone() != x
2.克隆对象与原对象的类型一样。即对任何的对象x:
x.clone().getClass() == x.getClass()
3.如果对象x的equals()方法定义恰当,那么下式应该成立:
x.clone().equals(x)
因为一个定义良好的equals()方法就应该是用来比较内容是否相等的。
- Java克隆clone的浅复制与深复制
- JAVA clone 深复制(深克隆)与浅复制(浅克隆)
- java clone 对象的深复制(深克隆)和浅复制(浅克隆)介绍
- (2.1.9)java的clone和浅复制克隆、深复制克隆
- JAVA深复制(深克隆)与浅复制(浅克隆)
- JAVA深复制(深克隆)与浅复制(浅克隆)
- JAVA深复制(深克隆)与浅复制(浅克隆)
- JAVA深复制(深克隆)与浅复制(浅克隆)
- JAVA深复制(深克隆)与浅复制(浅克隆)
- JAVA深复制(深克隆)与浅复制(浅克隆)
- JAVA深复制(深克隆)与浅复制(浅克隆)
- JAVA深复制(深克隆)与浅复制(浅克隆)
- JAVA深复制(深克隆)与浅复制(浅克隆)
- JAVA深复制(深克隆)与浅复制(浅克隆)
- JAVA深复制(深克隆)与浅复制(浅克隆)
- JAVA深复制(深克隆)与浅复制(浅克隆)
- JAVA深复制(深克隆)与浅复制(浅克隆)
- JAVA深复制(深克隆)与浅复制(浅克隆)
- 数据库入门
- No configuration found for the specified action解决办法
- 详细介绍JAVA和C++区别
- 并查集 模板
- POJ 2386 Lake Counting(DFS:求8连通分量的个数)
- Java克隆clone的浅复制与深复制
- Critical Section、Event、Mutex、Semaphores区别 for Windows
- 友情链接添加要适当,否则会适得其反
- [有向树的最小表示] poj 1635 Subway tree systems
- 深入了解Struts2返回JSON数据的原理及具体应用范例
- 倒转英文句子
- android中SQLite 应用
- 原生socket穿透HTTP代理服务器
- 远程访问mysql数据库