简介
使用场景
当我们需要生成一个实例的过程很复杂时,很难根据类来生成实例。我们可以通过复制来生成一个实例。 有时候我们想让生成实例的框架不依赖与具体的类,可以用原型模式。 对象种类繁多,无法将他们整合到一个类的时候。
实现方式1-- 实现Cloneable 接口
java为我们提供一个接口Cloneable,只需要我们实现该接口,并重写Object的clone()方法,我们就可以完成克隆。
public class Person implements Cloneable {
private String name;
private int age;
public Person ( String name, int age) {
this . name = name;
this . age = age;
}
@Override
protected Person clone ( ) throws CloneNotSupportedException {
Person person = null;
person = ( Person) super . clone ( ) ;
return person;
}
@Override
public String toString ( ) {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}' ;
}
}
public class Client {
public static void main ( String[ ] args) {
Person tom = new Person ( "tom" , 18 ) ;
try {
Person clone = tom. clone ( ) ;
System. out. println ( clone) ;
} catch ( CloneNotSupportedException e) {
e. printStackTrace ( ) ;
}
}
}
其实这里有一个问题,当属性为引用类型(不包括String)时就会有一个问题,并不会对引用类型的属性进行复制。我们称之为浅拷贝。
public class Person implements Cloneable {
private String name;
private int age;
private Person friend;
public Person ( String name, int age) {
this . name = name;
this . age = age;
}
public Person ( String name, int age, Person friend) {
this . name = name;
this . age = age;
this . friend = friend;
}
public String getName ( ) {
return name;
}
public void setName ( String name) {
this . name = name;
}
public Person getFriend ( ) {
return friend;
}
public void setFriend ( Person friend) {
this . friend = friend;
}
@Override
protected Person clone ( ) throws CloneNotSupportedException {
Person person = null;
person = ( Person) super . clone ( ) ;
return person;
}
@Override
public String toString ( ) {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", friend=" + friend +
'}' ;
}
}
public class Client {
public static void main ( String[ ] args) {
Person jerry = new Person ( "Jerry" , 16 ) ;
Person tom = new Person ( "tom" , 18 , jerry) ;
try {
Person clone = tom. clone ( ) ;
clone. getFriend ( ) . setName ( "Jack" ) ;
System. out. println ( clone) ;
System. out. println ( tom) ;
} catch ( CloneNotSupportedException e) {
e. printStackTrace ( ) ;
}
}
}
我们发现 tom的朋友名字也发生了变化,这是不符合实际,也不是我们想要的。 所以我们需要重写clone()。
public class Person implements Cloneable {
private String name;
private int age;
private Person friend;
public Person ( String name, int age) {
this . name = name;
this . age = age;
}
public Person ( String name, int age, Person friend) {
this . name = name;
this . age = age;
this . friend = friend;
}
public String getName ( ) {
return name;
}
public void setName ( String name) {
this . name = name;
}
public Person getFriend ( ) {
return friend;
}
public void setFriend ( Person friend) {
this . friend = friend;
}
@Override
protected Person clone ( ) throws CloneNotSupportedException {
Person person = null;
person = ( Person) super . clone ( ) ;
if ( person. getFriend ( ) != null) {
person. setFriend ( person. getFriend ( ) . clone ( ) ) ;
}
return person;
}
@Override
public String toString ( ) {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", friend=" + friend +
'}' ;
}
}
public class Client {
public static void main ( String[ ] args) {
Person jerry = new Person ( "Jerry" , 16 ) ;
Person tom = new Person ( "tom" , 18 , jerry) ;
try {
Person clone = tom. clone ( ) ;
clone. setName ( "clone" ) ;
clone. getFriend ( ) . setName ( "Jack" ) ;
System. out. println ( clone) ;
System. out. println ( tom) ;
} catch ( CloneNotSupportedException e) {
e. printStackTrace ( ) ;
}
}
}
重写clone()后,就实现类引用类型属性的拷贝。但有一个缺点就是有多个引用类型,我们都需要在clone方法中重新克隆一份。比较麻烦,不利于维护。
实现方式2–实现Serializable
利用序列化来对对象进行深拷贝,使用输入输出流来对对象进行实现。
public class Person implements Serializable {
private String name;
private int age;
private Person friend;
public Person ( String name, int age) {
this . name = name;
this . age = age;
}
public Person ( String name, int age, Person friend) {
this . name = name;
this . age = age;
this . friend = friend;
}
public String getName ( ) {
return name;
}
public void setName ( String name) {
this . name = name;
}
public Person getFriend ( ) {
return friend;
}
public void setFriend ( Person friend) {
this . friend = friend;
}
@Override
public String toString ( ) {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", friend=" + friend +
'}' ;
}
}
public class CloneUtil {
public static < T extends Serializable > T clone ( T obj) {
T clone = null;
ByteArrayOutputStream bos = null;
ObjectOutputStream oos = null;
ByteArrayInputStream bis = null;
ObjectInputStream ois = null;
try {
bos = new ByteArrayOutputStream ( ) ;
oos = new ObjectOutputStream ( bos) ;
oos. writeObject ( obj) ;
bis = new ByteArrayInputStream ( bos. toByteArray ( ) ) ;
ois = new ObjectInputStream ( bis) ;
clone = ( T) ois. readObject ( ) ;
} catch ( Exception e) {
e. printStackTrace ( ) ;
} finally {
try {
ois. close ( ) ;
bis. close ( ) ;
oos. close ( ) ;
bos. close ( ) ;
} catch ( IOException e) {
e. printStackTrace ( ) ;
}
}
return clone;
}
}
public class Client {
public static void main ( String[ ] args) {
Person jerry = new Person ( "Jerry" , 16 ) ;
Person tom = new Person ( "tom" , 18 , jerry) ;
try {
Person clone = CloneUtil. clone ( tom) ;
clone. setName ( "clone" ) ;
clone. getFriend ( ) . setName ( "Jack" ) ;
System. out. println ( clone) ;
System. out. println ( tom) ;
} catch ( Exception e) {
e. printStackTrace ( ) ;
}
}
}