一、Cloneable 的用途
Cloneable和Serializable一样都是标记型接口,它们内部都没有方法和属性,implements Cloneable表示该对象能被克隆,能使用Object.clone()方法。如果没有implements Cloneable的类调用Object.clone()方法就会抛出CloneNotSupportedException。
Cloneable和Serializable一样都是标记型接口,它们内部都没有方法和属性,implements Cloneable表示该对象能被克隆,能使用Object.clone()方法。如果没有implements Cloneable的类调用Object.clone()方法就会抛出CloneNotSupportedException。
二、克隆的分类
1、浅克隆(
shallow clone
)
拷贝对象的时候仅仅拷贝对象本身和对象中的基本变量,而不拷贝对象中包含的引用所指向的对象。
2、深克隆(
deep clone
)
拷贝对象的时候不仅仅拷贝对象本身,同时拷贝对象所包含的的引用所指向的对象。
举例说明:
对象A1中包含对B1的引用,B1中包含对C1的引用。
浅拷贝A1得到A2,A2中依然包含对B1的引用,B1中依然包含对C1的引用。深拷贝则是对浅拷贝的递归,深拷贝A1得到A2,A2中包含对B2(B1的copy)的引用,B2中包含对C2(C1的copy)的引用。
三、克隆的举例
要让一个对象进行克隆,其实就是两个步骤:
1、让类实现java.lang.Cloneable接口
2、重写(override) Object类的clone()方法
代码实现:
package
com.tyxh.create;
public
class
Wife
implements
Cloneable {
private
int
id
;
private
String
name
;
public
int
getId() {
return
id
;
}
public
void
setId(
int
id) {
this
.
id
= id;
}
public
String getName() {
return
name
;
}
public
void
setName(String name) {
this
.
name
= name;
}
public
Wife(
int
id,String name) {
this
.
id
= id;
this
.
name
= name;
}
@Override
public
int
hashCode() {
final
int
prime = 31;
int
result = 1;
result = prime * result +
id
;
result = prime * result + ((
name
==
null
) ? 0 :
name
.hashCode());
return
result;
}
@Override
public
boolean
equals (Object obj) {
if
(
this
== obj)
return
true
;
if
(obj ==
null
)
return
false
;
if
(getClass() != obj.getClass())
return
false
;
Wife other = (Wife) obj;
if
(
id
!= other.
id
)
return
false
;
if
(
name
==
null
) {
if
(other.
name
!=
null
)
return
false
;
}
else
if
(!
name
.equals(other.
name
))
return
false
;
return
true
;
}
@Override
public
Object clone()
throws
CloneNotSupportedException {
return
super
.clone();
}
public
static
void
main(String[] args)
throws
CloneNotSupportedException {
Wife wife =
new
Wife(1,
"wang"
);
Wife wife2 =
null
;
wife2 = (Wife) wife.clone();
System.
out
.println(
"wife : "
+ wife);
System.
out
.println(
"wife2 : "
+ wife2);
wife.setName(
"tyxh"
);
System.
out
.println(
"wife : "
+ wife);
System.
out
.println(
"wife2 : "
+ wife2);
wife2.setName(
"sotaof"
);
System.
out
.println(
"wife : "
+ wife);
System.
out
.println(
"wife2 : "
+ wife2);
//上面两个输出的地址相同,克隆的只是引用
System.
out
.println(
"class same="
+(wife.getClass()==wife2.getClass()));
//true
System.
out
.println(
"object same="
+(wife==wife2));
//false 说明两个对象的地址不同
System.
out
.println(
"object equals="
+(wife.equals (wife2)));
//false
}
}
输入结果:
wife : com.tyxh.create.Wife@3795e3
wife2 : com.tyxh.create.Wife@3795e3
wife : com.tyxh.create.Wife@369415
wife2 : com.tyxh.create.Wife@3795e3
wife : com.tyxh.create.Wife@369415
wife2 : com.tyxh.create.Wife@ca8fb940
class same=true
object same=false
object equals=false
第一行和第二行相同的原因不是因为克隆后的wife和wife2地址相同,而是因为hashcode的缘故,我们注意hashcode的返回值
result = prime * result + ((
name
==
null
) ? 0 :
name
.hashCode());name变化的话,返回值就会发生改变。
如果你在hashcode方法中返回1,那么结果就会是@1;
当对wife的name值进行修改之后,wife的值变化了,而wife2的值没有变化;
当对wife2的name值进行修改之后,
wife2的值变化了
,而
wife的值没有变化
。
但是这并不代表wife和wife2的地址发生了改变,这仅仅能说明wife和wife2的值发生了改变。当我们注释掉hashCode()和equals()方法之后,再看一下输出结果:
wife : com.tyxh.create.Wife@3771ed5e
wife2 : com.tyxh.create.Wife@1896d2c2
wife : com.tyxh.create.Wife@3771ed5e
wife2 : com.tyxh.create.Wife@1896d2c2
wife : com.tyxh.create.Wife@3771ed5e
wife2 : com.tyxh.create.Wife@1896d2c2
class same=true
object same=false
object equals=false
通过结果可以看出,不管是对wife还是对wife2进行值的修改,它们的地址都没有改变。
四.浅克隆的举例
package
com.tyxh.create;
public
class
Husband
implements
Cloneable {
private
int
id
;
private
Wife
wife
;
public
Wife getWife() {
return
wife
;
}
public
void
setWife(Wife wife) {
this
.
wife
= wife;
}
public
int
getId() {
return
id
;
}
public
void
setId(
int
id) {
this
.
id
= id;
}
public
Husband(
int
id) {
this
.
id
= id;
}
@Override
public
int
hashCode() {
final
int
prime = 31;
int
result = 1;
result = prime * result +
id
;
return
result;
}
@Override
protected
Object clone()
throws
CloneNotSupportedException {
return
super
.clone();
}
@Override
public
boolean
equals(Object obj) {
if
(
this
== obj)
return
true
;
if
(obj ==
null
)
return
false
;
if
(getClass() != obj.getClass())
return
false
;
Husband other = (Husband) obj;
if
(
id
!= other.
id
)
return
false
;
return
true
;
}
/**
*
@param
args
*
@throws
CloneNotSupportedException
*/
public
static
void
main(String[] args)
throws
CloneNotSupportedException {
Wife wife =
new
Wife(1,
"jin"
);
Husband husband =
new
Husband(1);
Husband husband2 =
null
;
husband.setWife(wife);
husband2 = (Husband) husband.clone();
System.
out
.println(
"husband : "
+ husband);
System.
out
.println(
"husband2 : "
+ husband2);
System.
out
.println(
"husband class same="
+(husband.getClass()==husband2.getClass()));
//true
System.
out
.println(
"husband object same="
+(husband==husband2));
//false
System.
out
.println(
"husband object equals="
+(husband.equals(husband)));
//true
System.
out
.println(
"wife class same="
+(husband.getWife().getClass()==husband2.getWife().getClass()));
//true
System.
out
.println(
"wife object same="
+(husband.getWife()==husband2.getWife()));
//true 说明引用是同一个引用
System.
out
.println(
"wife object equals="
+(husband.getWife().equals(husband.getWife())));
//true
}
}
输入结果如下:
husband : com.tyxh.create.Husband@20
husband2 : com.tyxh.create.Husband@20
husband class same=true
husband object same=false
husband object equals=true
wife class same=true
wife object same=true
wife object equals=true
四.深克隆的举例
package
com.tyxh.create;
public
class
Husband
implements
Cloneable {
private
int
id
;
private
Wife
wife
;
public
Wife getWife() {
return
wife
;
}
public
void
setWife(Wife wife) {
this
.
wife
= wife;
}
public
int
getId() {
return
id
;
}
public
void
setId(
int
id) {
this
.
id
= id;
}
public
Husband(
int
id) {
this
.
id
= id;
}
@Override
public
int
hashCode() {
//myeclipse 自动生成的
final
int
prime = 31;
int
result = 1;
result = prime * result +
id
;
return
result;
}
@Override
protected
Object clone()
throws
CloneNotSupportedException {
Husband husband = (Husband)
super
.clone();
husband.
wife
= (Wife) husband.getWife().clone();
return
husband;
}
@Override
public
boolean
equals(Object obj) {
//myeclipse 自动生成的
if
(
this
== obj)
return
true
;
if
(obj ==
null
)
return
false
;
if
(getClass() != obj.getClass())
return
false
;
Husband other = (Husband) obj;
if
(
id
!= other.
id
)
return
false
;
return
true
;
}
/**
*
@param
args
*
@throws
CloneNotSupportedException
*/
public
static
void
main(String[] args)
throws
CloneNotSupportedException {
Wife wife =
new
Wife(1,
"jin"
);
Husband husband =
new
Husband(1);
Husband husband2 =
null
;
husband.setWife(wife);
husband2 = (Husband) husband.clone();
System.
out
.println(
"husband : "
+ husband);
System.
out
.println(
"husband2 : "
+ husband2);
System.
out
.println(
"husband class same="
+(husband.getClass()==husband2.getClass()));
//true
System.
out
.println(
"husband object same="
+(husband==husband2));
//false
System.
out
.println(
"husband object equals="
+(husband.equals(husband)));
//true
System.
out
.println(
"wife class same="
+(husband.getWife().getClass()==husband2.getWife().getClass()));
//true
System.
out
.println(
"wife object same="
+(husband.getWife()==husband2.getWife()));
//false 说明引用不是同一个引用
System.
out
.println(
"wife object equals="
+(husband.getWife().equals(husband.getWife())));
//true
}
}
输出结果如下:
husband : com.tyxh.create.Husband@20
husband2 : com.tyxh.create.Husband@20
husband class same=true
husband object same=false
husband object equals=true
wife class same=true
wife object same=false
wife object equals=true
五、通过反序列化克隆 (也是深克隆)
package
com.tyxh.create;
import
java.io.*;
public
class
BeanUtil {
@SuppressWarnings
(
"unchecked"
)
public
static
<T> T cloneTo(T src) {
ByteArrayOutputStream memoryBuffer =
new
ByteArrayOutputStream();
ObjectOutputStream out =
null
;
ObjectInputStream in =
null
;
T dist =
null
;
try
{
out =
new
ObjectOutputStream(memoryBuffer);
out.writeObject(src);
out.flush();
in =
new
ObjectInputStream(
new
ByteArrayInputStream(memoryBuffer.toByteArray()));
dist = (T) in.readObject();
}
catch
(Exception e) {
e.printStackTrace();
}
finally
{
if
(out !=
null
) {
try
{
out.close();
}
catch
(IOException e) {
e.printStackTrace();
}
}
if
(in !=
null
) {
try
{
in.close();
}
catch
(IOException e) {
e.printStackTrace();
}
}
}
return
dist;
}
public
static
void
main(String[] args) {
Husband husband =
new
Husband(1);
Wife wife =
new
Wife(1,
"jin"
);
husband.setWife(wife);
Husband husband2 = cloneTo(husband);
System.
out
.println(
"husband class same="
+(husband.getClass()==husband2.getClass()));
//true
System.
out
.println(
"husband object same="
+(husband==husband2));
//false
System.
out
.println(
"husband object equals="
+(husband.equals(husband)));
//true
System.
out
.println(
"wife class same="
+(husband.getWife().getClass()==husband2.getWife().getClass()));
//true
System.
out
.println(
"wife object same="
+(husband.getWife()==husband2.getWife()));
//false 说明引用不是同一个引用
System.
out
.println(
"wife object equals="
+(husband.getWife().equals(husband.getWife())));
//true
}
}
输出结果如下:
husband class same=true
husband object same=false
husband object equals=true
wife class same=true
wife object same=false
wife object equals=true
通过第二行可以看出,反序列化之后的husband2与husband不是同一个对象
通过第五行可以看出,反序列化属于一种深克隆,因为husband和husband2的wife对象不同