一、应用场景
- 循环遍历,循环中创建新的对象
- 设计模式 -- 原型模式
二、总结
1.浅拷贝与深拷贝
调用 object.clone 方法,即浅拷贝;
浅拷贝:原对象中的属性 与 拷贝对象中的属相指向了堆中同一个对象的
重写 object.clone 方法,对引用数据类型,进行 显示的clone 声明
深拷贝:对象中的属性值也进行了相应的拷贝
2.拷贝的彻底性
Class A 中 对 Class B 进行引用
Class B 中 对 Class C 进行引用
在 A 中进行深拷贝,仅仅是对 B 进行了拷贝,而未对 C 进行处理;所以 C 依然是浅拷贝
3.clone 与 new 的区别联系
new 在堆中开辟新的空间,并调用构造方法进行初始化,返回一个地址引用
clone 同样开辟新的空间,区别在于新的空间中的引用数据类型是否与原来的对象共用一个引用地址;所以才有深浅拷贝的区分
三、示例解释
1.基本数据类型与引用数据类型String
package com.java.study.test.unit1; public class Person implements Cloneable { private int age ; private String name ; public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Person(int age, String name) { super(); this.age = age; this.name = name; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } } public class PersonMain { /** * @param args * @throws CloneNotSupportedException */ public static void main(String[] args) throws CloneNotSupportedException { Person person = new Person(1,"1"); Person personClone = (Person) person.clone(); // 基本数据类型:深拷贝,原对象的数据变更,不影响拷贝后的对象中的属性的值 person.setAge(2); System.out.println(personClone.getAge()); // 引用数据类型:若在clone 中未显示声明克隆,则为浅拷贝,原对象中属性的改变影响新对象的值 // String 特殊:String 对象的不可变性,克隆的同时 personClone.name 生成了新的字符串对象,并将新对象的地址返回 // 即:不是深拷贝导致原对象与拷贝对象中的属性的地址不一致;而是String的不可变的特性 person.setName("2"); System.out.println(personClone.getName()); // 输出 1 // 如果Stirng 是浅拷贝,原对象与拷贝对象中的name属性指向堆中同一地址,原对象属性的改变会对克隆对象产生影响 System.out.println(person.getName() == personClone.getName()); }
结论:
基本数据类型是深拷贝
引用类型的String是特例,浅拷贝,最终的效果是深拷贝,原对象与克隆对象不共享属性在堆中的地址
2.引用数据类型
package com.java.study.test.unit1; public class Person implements Cloneable { private int age ; private String name ; private Friend friend ; public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Person(int age, String name) { super(); this.age = age; this.name = name; } public Friend getFriend() { return friend; } public void setFriend(Friend friend) { this.friend = friend; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } }
package com.java.study.test.unit1; public class Friend { private String gender ; public String getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } public Friend(String gender) { super(); this.gender = gender; } }
public static void main(String[] args) throws CloneNotSupportedException { Person person = new Person(1,"1"); Friend friend = new Friend("male"); person.setFriend(friend); Person personClone = (Person) person.clone(); // 输出 male System.out.println(personClone.getFriend().getGender()); // 输出 female // 说明引用数据类型默认为浅拷贝;共同指向堆中的同一地址 person.getFriend().setGender("female"); System.out.println(personClone.getFriend().getGender()); }
结论:引用数据类型默认为浅拷贝
3.
package com.java.study.test.unit1; public class Person implements Cloneable { private int age ; private String name ; private Friend friend ; public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Person(int age, String name) { super(); this.age = age; this.name = name; } public Friend getFriend() { return friend; } public void setFriend(Friend friend) { this.friend = friend; } @Override protected Object clone() throws CloneNotSupportedException { Person p = (Person) super.clone(); p.friend = (Friend) friend.clone(); return p; } }
package com.java.study.test.unit1; public class Friend implements Cloneable{ private String gender ; public String getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } public Friend(String gender) { super(); this.gender = gender; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } }
结论:深拷贝即对类中的每一个引用数据逐一进行克隆
4.泛型
public static void main(String[] args) throws CloneNotSupportedException { Person person = new Person(1,"1"); Person person1 = new Person(2,"2"); ArrayList<Person> list = new ArrayList<Person>(2); list.add(person); list.add(person1); @SuppressWarnings("unchecked") ArrayList<Person> copyList = (ArrayList<Person>) list.clone(); for(Person personCopy : copyList){ System.out.println("index:"+personCopy.getAge()+",name:"+personCopy.getName()); } // 浅拷贝 // person.setName("5"); // person1.setName("6"); // for(Person personCopy : copyList){ // System.out.println("index:"+personCopy.getAge()+",name:"+personCopy.getName()); // } // 深拷贝:遍历集合,对集合中的每一个对象进行拷贝处理 ArrayList<Person> newCopyList = new ArrayList<Person>(2); for(int index = 0 ; index < list.size() ; index ++){ newCopyList.add((Person) list.get(index).clone()); } person.setName("5"); person1.setName("6"); for(Person personCopy : newCopyList){ System.out.println("index:"+personCopy.getAge()+",name:"+personCopy.getName()); } }
结论:泛型中的拷贝,要遍历泛型对每一个对象进行克隆
四、参考博客
详解Java中的clone方法 -- 原型模式
使用序列化实现对象的拷贝