一个类实现该接口表明该类的实例通过java.lang.Object#clone()方法拷贝字段的字段是合法的。
在一个没有实现该接口的实例上调用对象的clone方法会抛出CloneNotSupportedException异常。
通常,类实现该接口应该用public重写Object.clone方法(protected)。
注意,该接口没包含clone方法,因此,仅仅实现该接口是不可能克隆对象,即使通过反射调用克隆方法,也不能保证它会成功。
克隆一个对象是一个对象的不同标识和相同的内容,定义克隆,一个类必须实现Cloneable接口并且使用public重写对象的clone方法。此时,
克隆接口没有包含任何克隆方法,对象的clone方法是protected。
//没有实现该接口的实例上调用对象的clone方法会抛出CloneNotSupportedException异常
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
public
class
Person {
private
String name;
public
Person(String name) {
this
.name = name;
}
public
String getName() {
return
name;
}
public
static
void
main(String[] args) {
Person p =
new
Person(
"Sam"
);
try
{
Person pClone = (Person)p.clone();
System.out.println(pClone.getName());
}
catch
(CloneNotSupportedException e) {
e.printStackTrace();
}
}
}
|
//如果类想允许客户端克隆它的实例,必须使用public修饰符重写对象的clone方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
public
class
Person
implements
Cloneable {
private
String name;
public
Person(String name) {
this
.name = name;
}
public
String getName() {
return
name;
}
@Override
public
Person clone() {
try
{
return
(Person)
super
.clone();
}
catch
(CloneNotSupportedException e) {
e.printStackTrace();
throw
new
RuntimeException();
}
}
public
static
void
main(String[] args) {
Person p =
new
Person(
"Sam"
);
Person pClone = p.clone();
//如果clone不是public,不能调用
System.out.println(pClone.getName());
}
}
|
怎样实现clone方法?
如果在一个non-final类中重写clone方法,你应该通过调用super.clone返回一个对象。
如果所有类的父类都服从这个规则,则调用super.clone将最终调用Object.clone方法,创建一个正确类的实例。
//若下面的类没有服从该规则
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
public
class
Animal
implements
Cloneable {
private
String name;
public
Animal(String name) {
this
.name = name;
}
public
String getName() {
return
name;
}
public
String bark() {
return
"This is how i bark, better care not"
;
}
public
Animal clone() {
//当创建正确类的实例违法了调用super.clone()
return
new
Animal(name);
}
}
public
class
Dog
extends
Animal {
public
Dog(String name) {
super
(name);
}
public
String bark() {
return
"Bow Bow!!"
;
}
public
Dog clone() {
return
(Dog)
super
.clone();
}
}
public
class
CloneableTest {
public
static
void
main(String[] args) {
Dog dog =
new
Dog(
"Puppy"
);
Dog dogClone = dog.clone();
//无法转换类型
System.out.println(dogClone.getName());
}
}
Exception in thread
"main"
java.lang.ClassCastException: Animal cannot be cast to Dog
at Dog.clone(Dog.java:
13
)
at CloneableTest.main(CloneableTest.java:
6
)
|
一旦从super.clone()中获得了对象,需要根据类的性质可能做一些修改
如果每个字段包含一个原始类型的值or引用一个不可变对象,不需要进一步处理。
如果引用了可变对象,为了克隆工作正常,它要求调用这些可变引用的clone方法。
//克隆可变引用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
public
class
Person
implements
Cloneable {
private
String name;
private
Date dob;
public
Person(String name, Date dob) {
this
.name = name;
this
.dob = dob;
}
public
String getName() {
return
name;
}
public
Date getDob() {
return
dob;
}
@Override
public
Person clone() {
Person p;
try
{
p = (Person)
super
.clone();
p.dob = (Date) dob.clone();
return
p;
}
catch
(CloneNotSupportedException e) {
e.printStackTrace();
throw
new
RuntimeException();
}
}
public
static
void
main(String[] args) {
Person p =
new
Person(
"Sam"
,
new
Date());
Person pClone = p.clone();
System.out.println(pClone.getName());
System.out.println(pClone.getDob());
System.out.println(pClone.getDob() == p.getDob());
}
}
|
若有final字段指向可变的对象,为了是一个类可克隆,可能需要从一些字段中移除final修饰符(deep clone)。
如果实现一个线程安全可克隆类,注意它的clone方法必须正确同步就像任何其他方法一样。
实现clone方法非常棘手,避免实现它,寻找其他可代替方法