关于Cloneable接⼝和clone⽅法
1、使⽤
创建对象有两种⽅式: new 和 clone
当⼀个对象创建过程复杂,我们是否可以根据已有的对象直接来克隆⼀份,⽽不必关系创建的细节呢(原型模式)。1.1 Java Object根类默认提供了clone⽅法:
protected native Object clone() throws CloneNotSupportedException;
⼀个本地⽅法,protected权限:这样做是为避免我们创建每⼀个类都默认具有克隆能⼒ 
1.2 实现Cloneable接⼝
我们要使⽤⼀个对象的clone⽅法,必须Cloneable接⼝,这个接⼝没有任何实现,跟 Serializable⼀样是⼀种标志性接⼝如果不实现Cloneable接⼝,会抛出CloneNotSupportedException异常
重写clone⽅法,使⽤public修饰(否则外部调⽤不到),调⽤⽗类的clone⽅法
如下:
public class CloneModel implements  Cloneable{
private String name;
private int age;
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public String toString() {
return"CloneModel{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
1.3、Object.clone() 与构造⽅法
我们看⼀个例⼦:
CloneModel类:
public class CloneModel implements  Cloneable{
private String name;
private int age;
public CloneModel(){
System.out.println("will new a instance");
}
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public String toString() {
return"CloneModel{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
当我们调⽤此对象的clone⽅法时,构造⽅法并没有被调⽤,所以我说创建⼀个对象new和clone是两条路
public static void main(String[] args) throws CloneNotSupportedException {
CloneModel cloneModel = new CloneModel();
System.out.println(cloneModel.clone());
}
打印:
CloneModel{name='null', age=0}
2、重写clone⽅法原则
x.clone != x将会是true;
x.clone().getClass()==x.getClass()将会是true(不是绝对的,但建议这么做)
x.clone().equals(x)将会是true(不是绝对的,但建议这么做)
3、浅克隆和深克隆
3.1 默认clone⽅法时浅克隆
Object默认的clone⽅法实际是对域的简单拷贝,对于简单数据类型,是值的拷贝;
对于复杂类型的字段,则是指针地址的拷贝,clone后的对象和原对象指向的还是⼀个地址空间所以说默认的clone⽅法时浅克隆。
例⼦:
class Model2{
int height;
}
public class CloneModel implements  Cloneable{
private String name;
private int age;
private Model2 model2;
public CloneModel() {
}
public Model2 getModel2() {
return model2;
}
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public String toString() {
return "CloneModel{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
View Code
clone之后⽐较复杂对象是否相等
public static void main(String[] args) throws CloneNotSupportedException {
CloneModel cloneModel1 = new CloneModel();
CloneModel cloneModel2 = (CloneModel)cloneModel1.clone();
System.out.Model2()==Model2());
}
执⾏返回:true
3.2 如何实现深克隆
还是上⾯的例⼦,我们改下代码
class Model2 implements Cloneable{
int height;
@Override
public Object clone() throws CloneNotSupportedException {
System.out.println("clone Model2");
return super.clone();
}
}
public class CloneModel implements  Cloneable{
private String name;
private int age;
private Model2 model2;
public CloneModel() {
}
public Model2 getModel2() {
return model2;
}
public void setModel2(Model2 model2) {
}
@Override
public CloneModel clone() throws CloneNotSupportedException {
CloneModel cloneModelTemp = (CloneModel)super.clone();
cloneModelTemp.setModel2((Model2().clone());
return cloneModelTemp;
}
@Override
public String toString() {
return "CloneModel{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
View Code
再次测试下:
public static void main(String[] args) throws CloneNotSupportedException {
CloneModel cloneModel1 = new CloneModel();
CloneModel cloneModel2 = cloneModel1.clone();
System.out.Model2()==Model2());
}
执⾏返回:false
这么做就要在super.clone的基础上继续对⾮基本类型的对象递归的再次clone.显然这么⽅式是繁琐的且不可靠的。
有没有其他的⽅式呢?有序列化
3.3 序列化实现深度克隆
(1) 使⽤java⾃⾝的序列化转为⼆进制数,再反序列化为对象
上⾯的例⼦改造下
import java.io.Serializable;
class Model2 implements Serializable {
int height;
}
public class CloneModel implements Serializable {
private String name;
private int age;
private Model2 model2;
public CloneModel() {
}
public Model2 getModel2() {
return model2;
}
}
View Code
测试代码:
import st.CloneModel;
import java.io.*;
public class YfTest {
public static <T extends Serializable> T deepCloneObject(T object) throws IOException {        T deepClone = null;
ObjectInputStream ois = null;
try(ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
)
{
oos.writeObject(object);
ByteArrayInputStream bais = new ByteArrayInputStream(baos
.toByteArray());
ois = new ObjectInputStream(bais);
deepClone = (adObject();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
} finally {
if(ois != null){
ois.close();
}
}
return deepClone;
}
public static void main(String[] args) throws IOException {
CloneModel cloneModel1 = new CloneModel();
CloneModel cloneModel2 = deepCloneObject(cloneModel1);
System.out.Model2()==Model2());
}
}
View Code
测试输出:false
(2)其他序列化⽅式,如对象序列化json字符串再反序列化为对象
我们使⽤google的gson来进⾏序列化,上代码
le.gson.Gson;
import java.io.Serializable;
class Model2 implements Serializable {
int height;
}
public class CloneModel implements Serializable {
private String name;
private int age;
private Model2 model2;
public CloneModel() {
}
public Model2 getModel2() {
return model2;
}
public CloneModel deepClone() {
Gson gson = new Gson();
return gson.Json(this), CloneModel.class);
}
}
View Code
测试代码:
public static void main(String[] args) throws IOException {
CloneModel cloneModel1 = new CloneModel();
CloneModel cloneModel2 = cloneModel1.deepClone();
System.out.Model2()==Model2());
clone}
执⾏返回:false
性能对⽐测试:
上代码:
public static void main(String[] args) throws IOException {
CloneModel cloneModel1 = new CloneModel();
long time1 = System.currentTimeMillis();
for(int i=0;i<1000;i++){
//            CloneModel cloneModel2 = cloneModel1.deepClone();
CloneModel cloneModel2 = deepCloneObject(cloneModel1);
}
long time2 = System.currentTimeMillis();
System.out.println((time2-time1)+"ms");
}
循环1000次
Serializable耗时:118ms
json耗时:167ms
对⽐Serializable gson
易⽤性对象要实现Serializable,依赖的⼦元素依然要实现此接⼝,不易扩展⽆要求,额外的⼯具控制,易⽤使⽤性能对⽐1000次clone耗时118ms,稍好1000次clone耗时167ms

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。