浅拷贝
Java在复制一个对象的时候,对于其基本数据类型,复制了他的值;对于其引用数据类型,复制了他的引用,并没有重新new一个对象
如何实现浅拷贝
clone()
方法
在 Java 中,所有的 Class 都继承自 Object ,而在 Object 上,存在一个 clone() 方法,它被声明为了native protected ,所以我们可以在其子类中,使用它,并且不用关心内部实现。
因为native关键字:用来修饰方法,被修饰后的方法,看不见方法体。底层调用了C/C++代码。
所有需要调用clone()的类都必须实现Cloneable,该接口没有抽象方法,理解成一个标记来表示允许被拷贝。
import java.io.Serializable;
public class Person implements Cloneable {
public int age;
public String name;
public Student stu;
public Person(int age, String name, Student stu) {
super();
this.age = age;
this.name = name;
this.stu = stu;
}
public Person() {
super();
}
@Override
protected Object clone() throws CloneNotSupportedException {
// TODO Auto-generated method stub
return super.clone();
}
}
public class Student{
public int age;
public String name;
public Student(int age, String name) {
super();
this.age = age;
this.name = name;
}
public Student() {
super();
}
}
public class Test {
public static void main(String[] args) throws ClassNotFoundException, IOException {
Student s=new Student(19,"学生");
Person p=new Person(20,"人",s);
try {
Person c = (Person)p.clone();
System.out.println("拷贝前:");
System.out.println("Person的年龄:"+p.age);
System.out.println("Person的姓名:"+p.name);
System.out.println("Student的年龄:"+p.stu.age);
System.out.println("Student的姓名:"+p.stu.name);
System.out.println("-----------------------------------");
System.out.println("拷贝后:");
System.out.println("Person的年龄:"+c.age);
System.out.println("Person的姓名:"+c.name);
System.out.println("Student的年龄:"+c.stu.age);
System.out.println("Student的姓名:"+c.stu.name);
System.out.println("age是否是相同:"+(c.age==p.age));
System.out.println("name是否是为一个引用:"+(c.name==p.name));
System.out.println("Student是否是一个引用:"+(c.stu==p.stu));
} catch (CloneNotSupportedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
运行结果:
可以看到Student、String这两个引用数据类型在拷贝后仍是一个引用,即没有new出新对象,基本数据类型是拷贝了一个值。
深拷贝
Java在复制一个对象的时候,对于其基本数据类型,复制了他的值;对于其引用数据类型,重新new一个对象,并复制了该引用类型的成员变量。
如何实现深拷贝
- 序列化
序列化这个对象再反序列化回来,就会得到一个新对象。
什么是序列化和反序列化?
序列化:把对象转为字节序列,对象的输出过程称为序列化。
反序列化:把字节序列转为对象,对象的读取过程称为反序列化。
import java.io.Serializable;
public class Person implements Serializable {
public int age;
public String name;
public Student stu;
public Person(int age, String name, Student stu) {
super();
this.age = age;
this.name = name;
this.stu = stu;
}
public Person() {
super();
}
}
//在序列化某个对象的过程中,属性是引用数据类型,引用数据类型也要实现Serializable
public class Student implements Serializable{
public int age;
public String name;
public Student(int age, String name) {
super();
this.age = age;
this.name = name;
}
public Student() {
super();
}
}
public class Test {
public static void main(String[] args) throws ClassNotFoundException, IOException {
Student s=new Student(25,"学生");
Person p=new Person(19,"人",s);
System.out.println("序列化前:");
System.out.println("Person的年龄:"+p.age);
System.out.println("Person的姓名:"+p.name);
System.out.println("Student的年龄:"+p.stu.age);
System.out.println("Student的姓名:"+p.stu.name);
FileOutputStream os=new FileOutputStream("Test.txt");
ObjectOutputStream oos=new ObjectOutputStream(os);
oos.writeObject(p);
FileInputStream fis=new FileInputStream("Test.txt");
ObjectInputStream ois=new ObjectInputStream(fis);
Person readObject = (Person)ois.readObject();
oos.close();
os.close();
ois.close();
fis.close();
System.out.println("-----------------------------------");
System.out.println("序列化后:");
System.out.println("Person的年龄:"+readObject.age);
System.out.println("Person的姓名:"+readObject.name);
System.out.println("Student的年龄:"+readObject.stu.age);
System.out.println("Student的姓名:"+readObject.stu.name);
System.out.println("age是否是相同:"+(readObject.age==p.age));
System.out.println("name是否是为一个引用:"+(readObject.name==p.name));
System.out.println("Student是否是一个引用:"+(readObject.stu==p.stu));
}
}
运行结果:
从运行结果看出,这个Student类型成员变量和Sting类型成员变量均new了一个新的对象,而基本数据类型仅仅是复制了值给这个Person拷贝的新对象
- clone()
public class Person implements Cloneable {
public int age;
public String name;
public Student stu;
public Person(int age, String name, Student stu) {
super();
this.age = age;
this.name = name;
this.stu = stu;
}
public Person() {
super();
}
@Override
protected Object clone() throws CloneNotSupportedException {
Person pClone=(Person)super.clone();
pClone.stu=(Student)pClone.stu.clone();//pClone的stu指向了stu的拷贝
pClone.name=new String(pClone.name);//这里是为了让String这个引用数据类型也实现深拷贝
return pClone;
}
}
//Student实现Cloneable是为了在Person的clone()中可以拷贝一个新的Student,让Person的stu指向这个新的,来达到深拷贝的目的。即在深拷贝使用clone()时,该类中的成员变量是引用数据类型,该引用数据类型也要实现Cloneable
public class Student implements Cloneable{
public int age;
public String name;
public Student(int age, String name) {
super();
this.age = age;
this.name = name;
}
public Student() {
super();
}
@Override
protected Object clone() throws CloneNotSupportedException {
// TODO Auto-generated method stub
return super.clone();
}
}
public class Test {
public static void main(String[] args) throws ClassNotFoundException, IOException {
Student s=new Student(19,"学生");
Person p=new Person(20,"人",s);
try {
Person c = (Person)p.clone();
System.out.println("拷贝前:");
System.out.println("Person的年龄:"+p.age);
System.out.println("Person的姓名:"+p.name);
System.out.println("Student的年龄:"+p.stu.age);
System.out.println("Student的姓名:"+p.stu.name);
System.out.println("-----------------------------------");
System.out.println("拷贝后:");
System.out.println("Person的年龄:"+c.age);
System.out.println("Person的姓名:"+c.name);
System.out.println("Student的年龄:"+c.stu.age);
System.out.println("Student的姓名:"+c.stu.name);
System.out.println("age是否是相同:"+(c.age==p.age));
System.out.println("name是否是为一个引用:"+(c.name==p.name));
System.out.println("Student是否是一个引用:"+(c.stu==p.stu));
} catch (CloneNotSupportedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
运行结果:
从这个结果可以看出,对于Student引用数据类型,使用clone()也可以进行深拷贝