浅复制和深复制:
钱复制:克隆对象(A1)的所有变量都含有与原对象(A)相同的值,对象内部的引用对象(B)仍然指向原来的对象(B),浅复制仅仅复制所考虑的对象,而不复制它所引用的对象
深复制:克隆对象(A1)的所有变量都含有与原对象(A)相同的值,除去那些引用对象(B),那些引用对象(B)的变量将指向被复制过的新对象B1,而不再是原有的那些被引用的对象(B),深复制把要复制对象
所引用的对象都复制一遍
Java中的clone方法
(1)clone方法将对象复制一份并返回给被调用者,clone方法满足:
1.对任何的对象x,都有x.clone!=x 即克隆对象与原对象不是同一个对象
2.对任何的对象x,都有x.clone.getClass == x.getClass 克隆对象与原对象类型一样
3.如果对象x的equals方法定义恰当,那么x.clone.equals(x)应该成立
(2)java中对象的克隆
1.位了获取对象的一份拷贝,我们可以利用Object的clone方法
2.在派生子类中定义克隆方法,名字随意,可以叫clone(),并声明为public
3.在派生类的克隆方法中,调用super.clone()
4.派生类实现cloneable接口
1. 浅复制案例:
public class Professer{
String name;
int age;
public Professer(String name,int age) {
this.name = name;
this.age = age;
}
}
public class Student implements Cloneable{
String name;
int age;
Professer p;
Student(String name,int age,Professer p){
this.name = name;
this.age = age;
this.p = p;
}
public Student clone2() throws CloneNotSupportedException{
Student s = (Student) super.clone();
/********/
//如果professer类不实现cloneable接口,而且不写克隆方法供下面调用(s.p = p.clone3()方法被注释掉),则生成的结果如p1.png
//说明:1.克隆对象与原对象中的变量值是一样的,引用对象指向的是同一个对象;2.修改克隆对象中的普通变量对原对象没有影响,但修改克隆对象中引用对象的值,原对象中引用对象的值也发生改变
//********上述这种复制方式为浅复制*******//
//如果professer类实现了cloneable接口,而且写了克隆方法供下面调用(s.p = p.clone3()存在),则生成结果如p2.png
//说明:1.克隆对象与原对象中的变量值是一样的,引用对象指向的不是同一个对象;2.修改克隆对象中的普通变量对原对象没有影响,同时修改克隆对象引用对象的值,原对象中引用对象的值没变,克隆对象
//中的引用对象和元对象中的引用对象不是一个东西
//********上述这种复制方式为深复制******//
//s.p = p.clone3();
/*********/
return s;
}
public static void main(String[] args) throws CloneNotSupportedException {
Professer p3 = new Professer("王五", 50);
Student s1 = new Student("张三", 18, p3);
Student s2 = s1.clone2();
System.out.println("[v1]s1.name = " + s1.name + ";s1.age = " + s1.age + ";s1.p.name = " + s1.p.name + ";s1.p.age = " + s1.p.age);
System.out.println("[v1]s2.name = " + s2.name + ";s2.age = " + s2.age + ";s2.p.name = " + s2.p.name + ";s2.p.age = " + s2.p.age);
System.out.println();
s2.name = "李四";
s2.age = 20;
System.out.println("[v2]s1.name = " + s1.name + ";s1.age = " + s1.age + ";s1.p.name = " + s1.p.name + ";s1.p.age = " + s1.p.age);
System.out.println("[v2]s2.name = " + s2.name + ";s2.age = " + s2.age + ";s2.p.name = " + s2.p.name + ";s2.p.age = " + s2.p.age);
System.out.println();
s2.p.name = "赵六";
s2.p.age = 100;
System.out.println("[v3]s1.name = " + s1.name + ";s1.age = " + s1.age + ";s1.p.name = " + s1.p.name + ";s1.p.age = " + s1.p.age);
System.out.println("[v3]s2.name = " + s2.name + ";s2.age = " + s2.age + ";s2.p.name = " + s2.p.name + ";s2.p.age = " + s2.p.age);
}
}
总结:
(1).浅克隆中,克隆对象中普通变量和引用对象的值,都与原对象的值保持一致;
(2).浅克隆时,克隆对象和原对象不是同一个对象,但他们内部的【引用对象】指向的是同一个对象
(3).浅克隆时,修改普通变量,克隆对象和原对象互不影响,但修改引用对象时,两者引用对象的值同时改变
深克隆:
原对象A;
引用对象B;
克隆对象A1;
深复制的两种方式:
1. B实现cloneable接口,提供克隆方法,A实现cloneable接口,提供克隆方法的同时,调用B的克隆方法
2. 利用串行化来做深复制P:在Java里,深复制一个对象,常常可以先使对象实现serializabel接口,然后把对象写到一个流里,再从流里读出来,便可以重建对象;
=====>前提是要保证对象和对象内部所有引用到的对象都是可串行化的
案例1:
public class Professer implements Cloneable{
String name;
int age;
public Professer(String name,int age) {
this.name = name;
this.age = age;
}
public Professer clone3() throws CloneNotSupportedException{
return (Professer) super.clone();
}
}
public class Student implements Cloneable{
String name;
int age;
Professer p;
Student(String name,int age,Professer p){
this.name = name;
this.age = age;
this.p = p;
}
public Student clone2() throws CloneNotSupportedException{
Student s = (Student) super.clone();
/********/
//如果professer类不实现cloneable接口,而且不写克隆方法供下面调用(s.p = p.clone3()方法被注释掉),则生成的结果如p1.png
//说明:1.克隆对象与原对象中的变量值是一样的,引用对象指向的是同一个对象;2.修改克隆对象中的普通变量对原对象没有影响,但修改克隆对象中引用对象的值,原对象中引用对象的值也发生改变
//********上述这种复制方式为浅复制*******//
//如果professer类实现了cloneable接口,而且写了克隆方法供下面调用(s.p = p.clone3()存在),则生成结果如p2.png
//说明:1.克隆对象与原对象中的变量值是一样的,引用对象指向的不是同一个对象;2.修改克隆对象中的普通变量对原对象没有影响,同时修改克隆对象引用对象的值,原对象中引用对象的值没变,克隆对象
//中的引用对象和元对象中的引用对象不是一个东西
//********上述这种复制方式为深复制******//
s.p = p.clone3();
/*********/
return s;
}
public static void main(String[] args) throws CloneNotSupportedException {
Professer p3 = new Professer("王五", 50);
Student s1 = new Student("张三", 18, p3);
Student s2 = s1.clone2();
System.out.println("[v1]s1.name = " + s1.name + ";s1.age = " + s1.age + ";s1.p.name = " + s1.p.name + ";s1.p.age = " + s1.p.age);
System.out.println("[v1]s2.name = " + s2.name + ";s2.age = " + s2.age + ";s2.p.name = " + s2.p.name + ";s2.p.age = " + s2.p.age);
System.out.println();
s2.name = "李四";
s2.age = 20;
System.out.println("[v2]s1.name = " + s1.name + ";s1.age = " + s1.age + ";s1.p.name = " + s1.p.name + ";s1.p.age = " + s1.p.age);
System.out.println("[v2]s2.name = " + s2.name + ";s2.age = " + s2.age + ";s2.p.name = " + s2.p.name + ";s2.p.age = " + s2.p.age);
System.out.println();
s2.p.name = "赵六";
s2.p.age = 100;
System.out.println("[v3]s1.name = " + s1.name + ";s1.age = " + s1.age + ";s1.p.name = " + s1.p.name + ";s1.p.age = " + s1.p.age);
System.out.println("[v3]s2.name = " + s2.name + ";s2.age = " + s2.age + ";s2.p.name = " + s2.p.name + ";s2.p.age = " + s2.p.age);
}
}
案例2:
import java.io.Serializable;
public class Teacher implements Serializable{
private static final long serialVersionUID = 1L;
String name;
int age;
Teacher(String name,int age){
this.name = name;
this.age = age;
}
}
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class Student implements Serializable{
private static final long serialVersionUID = 1L;
String name;
int age;
Teacher t;
public Student(String name,int age,Teacher t){
this.name = name;
this.age = age;
this.t = t;
}
public Student deetClone() throws IOException, ClassNotFoundException{
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return (Student) ois.readObject();
}
public static void main(String[] args) throws ClassNotFoundException, IOException {
Teacher t = new Teacher("AAA",30);
Student s1 = new Student("A", 10, t);
Student s2 = s1.deetClone();
System.out.println("[v1]s1.name = " + s1.name + ";s1.age = " + s1.age + "; s1.t.name = " + s1.t.name + ";s1.t.age = " + s1.t.age);
System.out.println("[v1]s2.name = " + s2.name + ";s2.age = " + s2.age + "; s2.t.name = " + s2.t.name + ";s2.t.age = " + s2.t.age);
System.out.println();
s2.t.name = "BBB";
s2.t.age = 50;
System.out.println("[v1]s1.name = " + s1.name + ";s1.age = " + s1.age + "; s1.t.name = " + s1.t.name + ";s1.t.age = " + s1.t.age);
System.out.println("[v1]s2.name = " + s2.name + ";s2.age = " + s2.age + "; s2.t.name = " + s2.t.name + ";s2.t.age = " + s2.t.age);
}
}