1 Java的clone方法
1.1 为什么需要拷贝?
在实际编程过程中,我们要遇到这种情况:有一个对象A,在某一时刻A中已经包含了一些有效值,此时可能会需要一个和A完全相同新对象B,并且此后对B任何改动都不会影响到A中的值。也就是说,A与B是两个独立的对象,但B的初始值是由A对象确定的。用赋值语句是不能满足这种需求的,而通过实现clone()方法是最简单、最高效的手段。
1.2 什么是拷贝?
Java的所有类都默认继承java.lang.Object类,在java.lang.Object类中有一个方法clone()。JDK API的说明文档解释这个方法将返回Object对象的一个拷贝。要说明的有两点:
(1)拷贝对象返回的是一个新对象,而不是一个引用;
(2)拷贝对象与new新对象的区别就是:①这个拷贝已经包含了一些原来对象的信息,而不是对象的初始信息。 ②拷贝效率更高,因为Object类的clone()一个native方法,native方法的效率都是远高于非native方法。
1.2 如何使用clone()?
/**
* 一个很典型的调用clone()代码如下
*/
public class CloneClass implements Cloneable {
public int aInt;
public Object clone() {
CloneClass o = null;
try{
o = (CloneClass)super.clone();
} catch(CloneNotSupportedException e) {
e.printStackTrace();
}
return o;
}
}
有三个值得注意的地方:
(1)希望能实现clone功能的CloneClass类实现了Cloneable接口,这个接口属于java.lang包,java.lang包已经被缺省的导入类中;
(2)重载clone()方法;
(3)在clone()方法中调用super.clone(),指无论clone类的继承结构是什么样的,super.clone()直接或间接调用了java.lang.Object类的clone()方法;
(4)为了让其它类能调用这个clone类的clone()方法,重载之后要把clone()方法的属性设置为public;
2 浅拷贝
2.1 浅拷贝是什么?
浅拷贝:对象A复制出一个对象B来,修改对象B中的8中基本类型(包括装箱)的值和String,对象A中不被修改。修改对象B中的引用对象,由于只拷贝其引用,对象A中的引用对象也会被修改。
2.2 例子
public class AdEntity implements Cloneable {
public String adTitle;
public AdEntity(String adTitle) {
this.adTitle = adTitle;
}
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class BookshelfBanner implements Cloneable {
/**
* 标题
*/
public String title;
/**
* banner图片url
*/
public String banner;
/**
* 广告实体
*/
public AdEntity adEntity;
public BookshelfBanner(String title, AdEntity adEntity) {
this.title = title;
this.adEntity = adEntity;
}
/**
* 浅拷贝
* @return
*/
public Object clone() {
BookshelfBanner o = null;
try {
o = (BookshelfBanner) super.clone();
} catch (CloneNotSupportedException e) {
e.fillInStackTrace();
}
return o;
}
}
public class Test {
public static void main(String[] args) {
AdEntity adEntity = new AdEntity("小书亭");
BookshelfBanner banner1 = new BookshelfBanner("小书亭下载", adEntity);
BookshelfBanner banner2 = (BookshelfBanner) banner1.clone();
// banner2.adEntity.adTitle == "小书亭"
adEntity.adTitle = "小书亭改名啦"; // adEntity引用的adTitle改变了
// banner2.adEntity.adTitle == "小书亭改名啦" // 浅拷贝adEntity,会被修改
}
}
3 深拷贝
3.1 深拷贝是什么?
深拷贝:对象A复制出一个对象B来,修改对象B中的8中基本类型(包括装箱)的值和String,对象A中不被修改。修改对象B中的引用对象,由于引用对象是新创建对象,对象A中的引用对象不会被修改。
3.2 例子
public class AdEntity implements Cloneable {
public String adTitle;
public AdEntity(String adTitle) {
this.adTitle = adTitle;
}
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class BookshelfBanner implements Cloneable {
/**
* 标题
*/
public String title;
/**
* banner图片url
*/
public String banner;
/**
* 广告实体
*/
public AdEntity adEntity;
public BookshelfBanner(String title, AdEntity adEntity) {
this.title = title;
this.adEntity = adEntity;
}
/**
* 深拷贝
*
* @return
*/
public Object clone() {
BookshelfBanner o = null;
try {
o = (BookshelfBanner) super.clone();
if (adEntity != null) {
o.adEntity = (AdEntity) adEntity.clone();
}
} catch (CloneNotSupportedException e) {
e.fillInStackTrace();
}
return o;
}
}
public class Test {
public static void main(String[] args) {
AdEntity adEntity = new AdEntity("小书亭");
BookshelfBanner banner1 = new BookshelfBanner("小书亭下载", adEntity);
BookshelfBanner banner2 = (BookshelfBanner) banner1.clone();
// banner2.adEntity.adTitle == "小书亭"
adEntity.adTitle = "小书亭改名啦"; // adEntity引用的adTitle改变了
// banner2.adEntity.adTitle == "小书亭" // 深拷贝adEntity,不会被修改
}
}
4 还有一种深拷贝方法,将对象序列化
4.1 对象序列化是什么?
对象序列化却很耗时,在一些框架中,我们便可以感受到,它们往往将对象进行串行化后进行传递,耗时较多。
4.2 例子
public class AdEntity implements Serializable {
public String adTitle;
public AdEntity(String adTitle) {
this.adTitle = adTitle;
}
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class BookshelfBanner implements Serializable {
/**
* 标题
*/
public String title;
/**
* banner图片url
*/
public String banner;
/**
* 广告实体
*/
public AdEntity adEntity;
public BookshelfBanner(String title, AdEntity adEntity) {
this.title = title;
this.adEntity = adEntity;
}
/**
* 深拷贝
*
* @return
*/
public Object deepClone() throws IOException, OptionalDataException, ClassNotFoundException {
// 将对象写到流里
ByteArrayOutputStream bo = new ByteArrayOutputStream();
ObjectOutputStream oo = new ObjectOutputStream(bo);
oo.writeObject(this);
// 从流里读出来
ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());
ObjectInputStream oi = new ObjectInputStream(bi);
return (oi.readObject());
}
}
public class Test {
public static void main(String[] args) {
AdEntity adEntity = new AdEntity("小书亭");
BookshelfBanner banner1 = new BookshelfBanner("小书亭下载", adEntity);
BookshelfBanner banner2 = (BookshelfBanner) banner1.deepClone();
// banner2.adEntity.adTitle == "小书亭"
adEntity.adTitle = "小书亭改名啦"; // adEntity引用的adTitle改变了
// banner2.adEntity.adTitle == "小书亭" // 深拷贝adEntity,不会被修改
}
}