1.Java的基本数据类型和引用数据类型
基本数据类型包括byte、int、char、long、float、double、boolean和short八种基本数据类型 创建的对象在Java虚拟机栈中,
引用数据类型创建对象的时候会创建两个对象,一个在栈中,一般称作 ‘‘引用“,另一个存放在Java堆中。
2.浅克隆与深克隆
浅克隆的外在表现是:对象的基础类型对象相同,引用对象相同,包括存放在堆里的对象。也就是说所有的对其他对象的引用仍然指向原来的对象。
深克隆的外在表现是:复制前后的对象是相等的,也就是说引用的对象是相等的,而不是同一块Java堆中的内存。
对于对象来说相同和相等是充分不必要条件,相同一定相等,相等确往往可能不相同。
浅克隆是发生在栈中的拷贝,深克隆包括堆中对象的引用对象的拷贝。
3.Java对象的clone研究
<span style="font-family:Courier New;">package com.dusk.bean; public class Student implements Cloneable{ private String id; private Address address; public Student(){ } public Student(String id){ this.id=id; } public String getId() { return id; } public Address getAddress() { return address; } public void setAddress(Address address) { this.address = address; } @Override public String toString() { return "Student [id=" + id + "]"; } public void sayHello(){ System.out.println("hello,everyone!"); } @Override public Student clone() throws CloneNotSupportedException { return (Student) super.clone(); } }</span>
Address.java
<span style="font-family:Courier New;">package com.dusk.bean; public class Address { <span style="white-space:pre"> </span>private String address; <span style="white-space:pre"> </span>public String getAddress() { <span style="white-space:pre"> </span>return address; <span style="white-space:pre"> </span>} <span style="white-space:pre"> </span>public void setAddress(String address) { <span style="white-space:pre"> </span>this.address = address; <span style="white-space:pre"> </span>}</span>
}
Client.java
<span style="font-family:Courier New;">package com.dusk; import org.junit.Test; import com.dusk.bean.Student; public class Client { @Test public void test() throws Exception { Student stu1=new Student("1"); Student stu2=stu1.clone(); System.out.println(stu1==stu2); System.out.println(stu1.getAddress()==stu2.getAddress()); } }</span>
运行结果:
<span style="font-family:Courier New;">false true </span>
结论: Object提供的clone方法默认是浅克隆操作,对Student对象中的address没有进行clone操作。
4.同理对System.arraycopy进行验证,上代码:
<span style="font-family:Courier New;">package com.dusk; import org.junit.Test; import com.dusk.bean.Student; public class Test5 { @Test public void test() { Student[] arr1=new Student[]{new Student("1"),new Student("2"),new Student("3"),new Student("4")}; Student[] arr2=new Student[4]; System.arraycopy(arr1, 0, arr2, 0, 4); for(int i=0;i<arr2.length;i++){ System.out.println(arr1[i]==arr2[i]); } } } </span>
运行结果:
<span style="font-family:Courier New;">true true true true</span>
发现,System.arraycopy提供的也是浅克隆。
如果实现深克隆怎么办? 答案就是自己重写clone方法。
例如:
<span style="font-family:Courier New;"><span style="white-space:pre"> </span>@Override public Student clone() throws CloneNotSupportedException { Student stu=new Student(); stu.setId(this.id); stu.setAddress(new Address()); return stu; }</span>
结果肯定是:
<span style="font-family:Courier New;">false false</span>
是不是到此为止了?怎么可能,
如果我们把Address也实现了Cloneable怎么样?
Address.java变身为
<span style="font-family:Courier New;">package com.dusk.bean; public class Address implements Cloneable{ @Override protected Object clone() throws CloneNotSupportedException { // TODO Auto-generated method stub return super.clone(); } }</span>
继续调用3中的场景, 结果是:
<span style="font-family:Courier New;">false true </span>
尽然不是我预想的递归调用,看来如果自己的对象引用比较深的情况下做深克隆,自能自己退下自己的苦果了。
只能这样了吗?
看我必杀技,ObjectOutputStream和ObjectInputStream,祭法宝:
<span style="font-family:Courier New;">package com.dusk; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import org.junit.Test; import com.dusk.bean.Address; import com.dusk.bean.Student; public class Client{ @Test public void test() throws CloneNotSupportedException { Student stu1=new Student("1"); Address add = new Address(); stu1.setAddress(add); Student stu2=(Student) deepCopy(stu1); System.out.println(stu1==stu2); System.out.println(stu1.getAddress()==stu2.getAddress()); } private Object deepCopy(Object obj){ //将对象写到流里 try { ByteArrayOutputStream bo=new ByteArrayOutputStream(); ObjectOutputStream oo; oo = new ObjectOutputStream(bo); oo.writeObject(obj); //从流里读出来 ByteArrayInputStream bi=new ByteArrayInputStream(bo.toByteArray()); ObjectInputStream oi=new ObjectInputStream(bi); return(oi.readObject()); } catch (Exception e) { e.printStackTrace(); } return obj; } }</span>
结果:
<span style="font-family:Courier New;">false false</span>
完美的解决了对象多次套用的深克隆问题。
只要思想不滑坡,办法总比困难多!