一、前言
拷贝的目的就是为了获得相同的对象,当需要属性值相同的对象时,不需要再重新一步一步创建
在Java中的拷贝需要实现Clonable接口,重写Object的clone()方法;同时在Java中的拷贝也分为浅拷贝和深拷贝,其两者的区别就在于对 对象中引用数据类型的不同处理方法。即:
二、浅拷贝
(一)概念
(二)代码说明
public class Person implements Cloneable{
private String name;
private Integer age;
public String getName(){
return name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public Person clone() throws CloneNotSupportedException {
return (Person) super.clone();
}
public static void test01() throws CloneNotSupportedException {
Person p1=new Person();
p1.setName("小王");
p1.setAge(18);
Person p2=p1.clone();
System.out.println(p1+":"+p1.hashCode());
System.out.println(p2+":"+p2.hashCode());
}
运行结果:
Person{name='小王', age=18}:1324119927
Person{name='小王', age=18}:1915910607
通过上述代码 我们可以看出拷贝出的Person对象的存储哈希表上的哈希值不一样,说明两个对象的内存位置不同,即成功实现了对象的拷贝。下面的例子将进一步说明成员中引用类型哈希值的变化
Children类:实现Clonable接口
public class Children implements Cloneable{
private String name;
private Integer age;
public String getName(){
return name;
}
public Integer getAge() {
return age;
}
public void setName(String name) {
this.name = name;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Children{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
Person类 其中存在Children类型的成员变量--->即引用类型变量
public class Person implements Cloneable{
private String name;
private Integer age;
private Children child;
public String getName(){
return name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public void setName(String name) {
this.name = name;
}
public void setChild(Children child) {
this.child = child;
}
public Children getChild() {
return child;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public Person clone() throws CloneNotSupportedException {
// return (Person) super.clone();
Person clone=(Person)super.clone();//克隆Person对象
return clone;
}
}
//以下为测试类
public static void test02() throws CloneNotSupportedException {
Person p1=new Person();
p1.setName("小王");
p1.setAge(28);
Children children1=new Children();
children1.setName("张伟");
children1.setAge(5);
p1.setChild(children1);
Person p2=p1.clone();
System.out.println(p1+":对象的哈希值"+p1.hashCode()+":成员变量的哈希值"+p1.getChild().hashCode());
System.out.println(p2+":对象的哈希值"+p2.hashCode()+":成员变量的哈希值"+p1.getChild().hashCode());
}
测试结果:
Person{name='小王', age=28}:对象的哈希值990368553:成员变量的哈希值1096979270
Person{name='小王', age=28}:对象的哈希值2093176254:成员变量的哈希值1096979270
说明 浅拷贝的对象占用不同的内存位置,但引用类型的成员 哈希值一样 ,则说明两对象之间的变量会相互影响。任一个变量的变化会影响到另一个变量。
通过上述的实例,我们归纳以下步骤:
三、深拷贝
(一)概念
(二)代码说明
对Children类重写clone()方法:
@Override
protected Children clone() throws CloneNotSupportedException {
return (Children) super.clone();
对Person重写clone()方法:
@Override
public Person clone() throws CloneNotSupportedException {
// return (Person) super.clone();
Person clone=(Person)super.clone();//克隆Person对象
clone.setChild(child.clone()); //克隆Person中的成员变量 通过成员变量child的副本传参
return clone;
}
测试类:
public static void test04() throws CloneNotSupportedException {
Person p1=new Person();
p1.setName("小王");
p1.setAge(28);
Children children1=new Children();
children1.setName("张伟");
children1.setAge(5);
p1.setChild(children1);
Person p2=p1.clone(); //克隆person对象 同时也对Children成员变量进行了克隆 即两者完全剥离
System.out.println(p1.getChild());
System.out.println(p2.getChild());
children1.setName("张三");//单独设置children1的属性
System.out.println(p1.getChild());
System.out.println(p2.getChild());
Children children2=p2.getChild();//此时p2为p1的副本 ,用p2调用getChild方法来获取children对象
children2.setName("张无忌"); //单独设置children2的属性
System.out.println(p1.getChild());
System.out.println(p2.getChild());
//打印出两个子对象的哈希值 两者哈希值不一样说明 两个对象的存储位置不一样
System.out.println(p1.getChild().hashCode());
System.out.println(p2.getChild().hashCode());
}
Children{name='张伟', age=5}
Children{name='张伟', age=5}
Children{name='张三', age=5}
Children{name='张伟', age=5}
Children{name='张三', age=5}
Children{name='张无忌', age=5}
668386784
1329552164
从上述代码可以分析出,对对象进行深拷贝后,改变对象中引用类型数据的值 不会影响到另一个对象,通过最后两行的哈希值也可以比较出 两个子对象的哈希值是不相同的,这样就实现了对象间关系的完全脱离,以免对其他对象的内容造成影响。
深拷贝步骤: