优点:主要用于对象复制,可克隆出来再做赋值修改以达到对象满足,减少new对象的性能损耗,克隆类似于new,但跟new不同,new是所有属性都是默认值,而克隆是带原型对象中的值。
缺点:逃避构造函数的约束。
分三部分:
1.浅复制
2.深复制
3.序列化反序列化实现深复制
以保时捷为例子,创建一台车,然后复制一台车,想要做到复制,只需在类中做两件事:
1.需要实现Cloneable 接口
2.继承Object的clone方法
浅复制
import java.util.Date;
/**
* 这是一个保时捷实体类
* porscheModel 保时捷型号
* interior 内饰
* wheelHub 轮毂规格
* date 生产时间
*/
public class Porsche implements Cloneable {
private String porscheModel;
private String interior;
private int wheelHub;
private Date date;
public Porsche(){
}
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
public String getPorscheModel() {
return porscheModel;
}
public void setPorscheModel(String porscheModel) {
this.porscheModel = porscheModel;
}
public String getInterior() {
return interior;
}
public void setInterior(String interior) {
this.interior = interior;
}
public int getWheelHub() {
return wheelHub;
}
public void setWheelHub(int wheelHub) {
this.wheelHub = wheelHub;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
}
测试:
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.FragmentActivity;
import android.util.Log;
import com.hdc.test.prototype.Porsche;
import java.util.Date;
/**
* 这是调用者
*/
public class MainActivity extends FragmentActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Date date = new Date(351213211);
Porsche porsche = new Porsche();
porsche.setPorscheModel("保时捷911");
porsche.setInterior("石榴红真皮内饰");
porsche.setWheelHub(20);
porsche.setDate(date);
try {
//浅复制
Porsche porsche2 = (Porsche) porsche.clone();
//打印
Log.d("TAG", "原型对象:" + porsche + "\n克隆对象:" + porsche2);
Log.d("TAG", "原型对象date的值:" + porsche.getDate() + "\n克隆对象date的值:" + porsche2.getDate());
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
}
结果:
克隆出了一个全新对象,值也都是一样的,引用地址也是一样的,但是浅克隆会有一个问题,就是当你把Date对象修改之后,克隆对象的值也会跟着改变。
测试:
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.FragmentActivity;
import android.util.Log;
import com.hdc.test.prototype.Porsche;
import java.util.Date;
/**
* 这是调用者
*/
public class MainActivity extends FragmentActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Date date = new Date(351213211);
Porsche porsche = new Porsche();
porsche.setPorscheModel("保时捷911");
porsche.setInterior("石榴红真皮内饰");
porsche.setWheelHub(20);
porsche.setDate(date);
Log.d("TAG", "修改前原型对象date的值:" + porsche.getDate());
try {
//浅复制
Porsche porsche2 = (Porsche) porsche.clone();
//克隆完成后修改date的值
date.setTime(325623262);
//打印
Log.d("TAG", "原型对象date的值:" + porsche.getDate() + "\n克隆对象date的值:" + porsche2.getDate());
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
}
结果:
克隆对象porsche2 时间也随之改变了,我在date修改前已经复制出来了,为什么还是会改变?因为porsche和porsche2 引用的是同一个对象,他们获取值的引用地址是一样的,当引用地址的值被改变之后,他们也随之改变,因此要避免这种情况需要用到深复制。
深复制
很简单,Porsche 实体类中的clone()方法做以下重写,把属性也进行克隆就好
@Override
public Object clone() throws CloneNotSupportedException {
Object obj = super.clone();
Porsche porsche = (Porsche) obj;
porsche.date = (Date) this.date.clone();
return obj;
}
结果:
这样就能保证,当引用地址值发生改变时,克隆对象中的值不会发生改变。
序列化与反序列化实现深复制
序列化之前实体类需要实现Serializable,clone方法返回父类的clone方法就行了,不需要重写。
import java.io.Serializable;
import java.util.Date;
/**
* 浅复制
* 这是一个保时捷实体类
* porscheModel 保时捷型号
* interior 内饰
* wheelHub 轮毂规格
* date 生产时间
*/
public class Porsche implements Cloneable, Serializable {
private String porscheModel;
private String interior;
private int wheelHub;
private Date date;
public Porsche() {
}
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
public String getPorscheModel() {
return porscheModel;
}
public void setPorscheModel(String porscheModel) {
this.porscheModel = porscheModel;
}
public String getInterior() {
return interior;
}
public void setInterior(String interior) {
this.interior = interior;
}
public int getWheelHub() {
return wheelHub;
}
public void setWheelHub(int wheelHub) {
this.wheelHub = wheelHub;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
}
测试:
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.FragmentActivity;
import android.util.Log;
import com.hdc.test.prototype.Porsche;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Date;
/**
* 这是调用者
*/
public class MainActivity extends FragmentActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Date date = new Date(351213211);
Porsche porsche = new Porsche();
porsche.setPorscheModel("保时捷911");
porsche.setInterior("石榴红真皮内饰");
porsche.setWheelHub(20);
porsche.setDate(date);
Log.d("TAG", "修改前原型对象date的值:" + porsche.getDate());
try {
//序列化和反序列化实现深复制
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(porsche);
byte[] bytes = bos.toByteArray();
ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bis);
Porsche porsche2 = (Porsche) ois.readObject();
//克隆完成后修改date的值
date.setTime(325623262);
//打印
Log.d("TAG", "原型对象date的值:" + porsche.getDate() + "\n克隆对象date的值:" + porsche2.getDate());
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
结果:
引用地址的值发生改变,克隆对象数据并未改变,这样一样可以实现深复制。
最后以new对象以及克隆对象的耗时测试作为总结:
模拟对象耗时操作:
/**
* 保时捷911实体类
* 模拟对象耗时操作,假设创建一个对象需要5秒
*/
public class Porsche911 implements Cloneable {
public Porsche911() {
try {
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.FragmentActivity;
import android.util.Log;
import com.hdc.test.prototype.Porsche911;
/**
* 这是调用者
*/
public class MainActivity extends FragmentActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//都创建1000个对象
testNew(1000);
testClone(1000);
}
//new的方式构建对象
private void testNew(int size) {
long startTime = System.currentTimeMillis();
for (int i = 0; i < size; i++) {
Porsche911 porsche911 = new Porsche911();
}
long endTime = System.currentTimeMillis();
Log.d("TAG", "New方式创建对象耗时:" + (endTime - startTime));
}
private void testClone(int size) {
long startTime = System.currentTimeMillis();
Porsche911 porsche911 = new Porsche911();
for (int i = 0; i < size; i++) {
try {
Porsche911 porsche9112 = (Porsche911) porsche911.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
long endTime = System.currentTimeMillis();
Log.d("TAG", "clone方式创建对象耗时:" + (endTime - startTime));
}
}
结果:
如果是很耗时的对象的话,效率差的不是一星半点。
已完成测试!有不对的地方欢迎指出,感恩。