关于java的深拷贝浅拷贝,其实就是将一个对象复制一下到一个新的对象。
1.创建对象的方式
1.1 通过new关键字
这个是最常见创建对象的方式,通过new关键字调用类的有参或者无参构造方法来创建对象。Object obj = new Object();
1.2 通过class的newInstance()方法
这种其实也是默认通过无参构造方法来创建对象,比如
1
| Faith faith = (Faith) Class.forName("com.faith.datastruct.tree.Faith").newInstance();
|
1.3 通过Constructor类的newInstance方法
这和第二种方法类时,都是通过反射机制来实现的,通过java.lang.relect.Constructor类的newInstance()方法指定某个构造器来创建对象
1
| Faith faith1 = (Faith) Class.forName("com.faith.datastruct.tree.Faith").getConstructor().newInstance();
|
实际上第二种方法利用 Class 的 newInstance() 方法创建对象,其内部调用还是 Constructor 的 newInstance() 方法。
1.4 利用clone方法
Clone方法是Object类中的方法,通过A.clone()方法会创建一个内容和对象A一模一样的对象B,clone克隆顾名思义就是创建一个一模一样的对象出来
1
| Faith faith2 = (Faith) faith.clone();
|
1.5 反序列化
序列化是把堆内存中的java对象数据,通过某种方式把对象存储到磁盘文件中或者传递给其他网络节点(在网上传输)。而反序列化则是把磁盘文件中的对象数据或者把网络节点上的对象数据,恢复成java对象模型的过程。
2.浅拷贝
代码实现
克隆类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| package com.faith.datastruct.tree;
public class CloneParentTest implements Cloneable { public CloneParentTest() { }
public CloneParentTest(String value1) { this.value1 = value1; this.value2 = new Faith(); }
public String getValue1() { return value1; }
public void setValue1(String value1) { this.value1 = value1; }
public Faith getValue2() { return value2; }
public void setValue2(String name,int age) { value2.setFaith(name,age); }
@Override protected Object clone() throws CloneNotSupportedException { return super.clone(); }
public String value1; public Faith value2; public void display(){ System.out.println("name:"+value1+","+value2); } }
|
Faith类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| package com.faith.datastruct.tree;
public class Faith { public String name; public int age; public void setFaith(String name,int age){ this.name = name; this.age = age; }
@Override public String toString() { return "Faith{" + "name='" + name + '\'' + ", age=" + age + '}'; }
}
|
运行代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, CloneNotSupportedException { CloneParentTest parentTest = new CloneParentTest("faith"); parentTest.setValue2("faith",25); System.out.println("p1:"+parentTest); System.out.println("p1.name:"+parentTest.getValue1().hashCode());
CloneParentTest cloneObj = (CloneParentTest) parentTest.clone(); System.out.println("p1:"+cloneObj); System.out.println("p1.name:"+cloneObj.getValue1().hashCode());
parentTest.display(); cloneObj.display();
parentTest.setValue2("acid",24); System.out.println("change value"); parentTest.display(); cloneObj.display();
}
|
运行效果
1 2 3 4 5 6 7 8 9 10
| p1:com.faith.datastruct.tree.CloneParentTest@1b6d3586 p1.name:97193474 p1:com.faith.datastruct.tree.CloneParentTest@4554617c p1.name:97193474 name:faith,Faith{name='faith', age=25} name:faith,Faith{name='faith', age=25} change value name:faith,Faith{name='acid', age=24} name:faith,Faith{name='acid', age=24}
|
如上的运行效果 最开始拷贝之后 cloneObj的非静态和parentTest的非静态字段值相同,引用类型也是,但是当运行到
1
| parentTest.setValue2("acid",24);
|
的时候改变了其中引用类型的值,其两个都发生了改变,可以得出 clone对于引用类型来说只不过copy了对于引用类型的指向
3.深拷贝
深拷贝:创建一个新对象,然后将当前对象的非静态字段复制到该新对象,无论该字段是值类型的还是引用类型,都复制独立的一份。当你修改其中一个对象的任何内容时,都不会影响另一个对象的内容。
4.如何实现深拷贝呢
第一种方法可以在Faith类中也去实现Cloneable接口,但是这个方法有个弊端 比如Faith类中又有其他的类 那么一层层下面都需要实现Clone接口不太建议使用。
第二种方法就是使用序列化
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public Object deepClone() throws Exception{ ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bis);
return ois.readObject(); }
|