Java中提供了三种对象的拷贝方式
分别是
- = 赋值运算符拷贝
- 拷贝构造函数
- clone()方法拷贝
由于Java不支持对运算符的重载,所以 = 赋值运算符拷贝对象只能够浅拷贝
我主要讲一下浅拷贝、深拷贝的区别以及拷贝构造方法和clone方法()拷贝对象
浅拷贝
浅拷贝又称为浅复制,浅克隆,浅拷贝是指拷贝时只拷贝对象本身(包括对象中的基本变量),而不拷贝对象包含的引用所指向的对象,拷贝出来的对象的所有变量的值都含有与原来对象相同的值,而所有对其他对象的引用都指向原来的对象,简单地说,浅拷贝只拷贝对象不拷贝引用。
深拷贝
深拷贝又称为深复制,深克隆,深拷贝不仅拷贝对象本身,而且还拷贝对象包含的引用所指向的对象,拷贝出来的对象的所有变量(不包含那些引用其他对象的变量)的值都含有与原来对象的相同的值,那些引用其他对象的变量将指向新复制出来的新对象,而不指向原来的对象,简单地说,深拷贝不仅拷贝对象,而且还拷贝对象包含的引用所指向的对象
得出结论:浅拷贝与深拷贝的 *本质 在于是否拷贝对象引用
拷贝构造方法
概念:Java 中的拷贝构造方法是一种使用该类的一个对象
构造另外一个对象的构造方法
拷贝构造方法与类构造方法相似,只用访问修饰符修饰,无返回值
public class Employee {
private int id;
private String name;
public Employee(Employee employee) {
}
}
这样就完成了一个浅拷贝的拷贝构造方法,幸运的是虽然Java不支持运算符重载,但是拷贝构造方法是可以“随意”重载的。
现在我们来为Employee类添加一个Date类属性,当我们想通过date类来获取当前时间时,需要创建一个date对象来访问,此时date对象就是一个引用,所以我们可以写出
public class Employee {
private int id;
private String name;
private Date startDate;
public Employee(Employee employee) {
this.id = employee.id;
this.name = employee.name;
this.startDate = new Date(employee.startDate.getTime());
}
}
这样的拷贝方法重载,来将拷贝构造方法拷贝对象时,将引用对象重新创建,让其指向新的引用来完成深拷贝
Clone()方法拷贝对象
Clone()方法需要继承CLoneable接口才能使用,并且要捕捉处理 CloneNotSupportedException异常,是为了防止意外的支持clone操作。
class People implements Cloneable{
private int age;
private String name;
private
public Objcet Clone(){
People obj = null;
try
{
obj = (People)super.clone(); //Object中需要识别你要克隆的对象
} catch (CloneNotSupportedException e)
{
System.out.println(e.toString());
}
return obj;
}
}
这样就完成了改写一个可以使用clone()方法克隆对象的类。
但是需要注意的是,这仅仅只是浅拷贝,和拷贝构造方法类似,只需要在克隆对象的时候,创建一个新的引用指向新对象即可,在Clone()方法中是这样写的
class People implements Cloneable{
private int age;
private String name;
private Date startime;//新添加的 引用属性
public Objcet Clone(){
People obj = null;
try
{
obj = (People)super.clone(); //Object中需要识别你要克隆的对象
} catch (CloneNotSupportedException e)
{
System.out.println(e.toString());
}
obj.startime = (Date)startime.clone();//针对引用属性的克隆语句
return obj;
}
}
这样就完成了对CLone()方法实现浅拷贝与深拷贝的解释
拷贝构造方法 VS Clone()方法拷贝
在Java中我个人倾向于拷贝构造方法,其优点有
- 拷贝构造方法实现更简单。不需要实现 Cloneable 接口,也不需要处理 CloneNotSupportedException
- clone 函数返回一个普通的 Object 类型的引用。还需要转成特定的类型。
不过CLone()方法看起来复杂,但其实更符合程序设计概论的规范,其使用了实现接口以及异常捕获来提高程序的健壮性。