参考:
下面学习 Java
中的 Object.clone()
方法 和 cloneable
接口的概念和使用,学习关于 强复制(克隆,拷贝)和浅复制 的区别和联系
主要内容:
Object.clone()
方法和cloneable
接口Object.clone()
方法的实现- 深复制和浅复制
Object.clone()
方法和
cloneable
接口
Object.clone()
方法和
cloneable
接口
Object.clone()
方法
Object
类是 Java
中类层次结构的根,是所有类的超类。新建一个类,如果没有继承超类,Java
默认使用 Object
类作为该类的超类
Object.clone()
方法格式如下:
protected native Object clone() throws CloneNotSupportedException;
功能:创建并返回复制对象
Cloneable
接口
Cloneable
接口没有任何方法,它仅用于表明类想要重载 Object.clone()
方法。如果没有继承该接口就重载 Object.clone()
方法,Object.clone()
方法将抛出 java.lang.CloneNotSupportedException
异常
Object.clone() 方法的实现
创建新类 Cloner
,继承接口 Cloneable
,并重载 clone
方法
import java.util.Arrays;
/**
* Created by zj on 2017/10/16.
*/
public class Cloner implements Cloneable {
private int num;
private String str;
private Person person;
public Cloner(int num, String str, Person person) {
this.num = num;
this.str = str;
this.person = person;
}
public void setNum(int num) {
this.num = num;
}
public void setStr(String str) {
this.str = str;
}
public void setName(String name) {
this.person.setName(name);
}
public void setAge(int age) {
this.person.setAge(age);
}
@Override
public String toString() {
return "Cloner{" +
"num=" + num +
", str='" + str + '\'' +
", person=" + person +
'}';
}
// @Override
// protected Object clone() throws CloneNotSupportedException {
// return super.clone();
// }
@Override
protected Object clone() {
Cloner cloner = null;
try {
cloner = (Cloner) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return cloner;
}
static class Person {
String name;
int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
}
重载方法 clone()
,调用超类的 clone()
方法即可实现对象复制,因为 clone()
方法会抛出检查时异常 CloneNotSupportedException
,所以修改代码如上所示
测试代码如下:
public static void main(String[] args) throws CloneNotSupportedException {
int num = 10;
String str = "str";
Person person = new Person("zj", 1111);
Cloner src = new Cloner(10, "str", person);
Cloner dst = (Cloner) src.clone();
System.out.println("Before...");
System.out.println(src);
System.out.println(dst);
dst.setNum(20);
dst.setStr("str2");
dst.setName("name");
dst.setAge(100);
System.out.println("After...");
System.out.println(src);
System.out.println(dst);
}
问题:创建一个类 Cloner
的实例 src
,并得到它的克隆对象 dst
,修改 dst
的值,发现 src
的部分属性也发生了变化
深复制和浅复制
参考:
使用 clone()
方法进行对象的复制,就是在堆上新建一个和原先对象同样大小的存储空间,将原先对象的内容复制到该存储空间
优点如下:
- 操作简单:仅需重载
clone()
方法即可 - 执行效率高:如果使用
new
关键字重新建一个对象,然后进行属性的复制,需要耗费大量的操作
缺点如下:
如果仅执行 super.clone()
方法进行复制,对复制对象的操作有可能会改变原先对象的属性
原始类型(primitive type)
参考:
Java
的原始类型就是指基本数据类型,即
byte
char
short
int
long
float
double
boolean
可变(mutable
),不可变(immutable
)对象
参考:
不可变对象指对象被创建后无法改变状态的对象,即每次对它进行操作都是产生了新的对象,如 String
而可变对象与之相反,对象在创建后,可以在本身发送改变,如 StringBuffer
浅复制
直接使用 Object.clone()
方法进行复制的操作属于浅复制
即如果该对象内部包含了对可变对象的引用,那么复制得到的新对象同样拥有对该可变对象的引用,所以在新对象中进行可变对象的操作后,原对象的属性也发生了变化
深复制
如果复制得到的对象的操作不会影响到原对象,那么这种操作就是深复制
为实现深复制,需要在重载 clone()
方法的时候对可变对象创建新的地址空间,
上面代码修改如下:
@Override
protected Object clone() {
Cloner cloner = null;
try {
cloner = (Cloner) super.clone();
cloner.person = new Person(this.person.name, this.person.age);
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return cloner;
}
重新测试,结果如下: