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>
只要思想不滑坡,办法总比困难多!