java cloneable 用途_java中cloneable的使用
什么是java中的淺克隆和深克隆?
淺克隆:克隆對象中的變量與之前對象的值相同,并且對象中的引用類型變量仍然指向原來對象引用類型變量的地址.
深克隆:克隆對象中的變量與之前對象的值相同,并且對象中的引用類型變量指向了新的對象的引用變量的地址.
要想實現克隆,只需定義的類聲明下cloneable這個標記性接口,并且衍生重寫Object類中就有的clone()方法即可.
為什么類要首先聲明cloneable標記接口,然后重寫clone()方法?因為不聲明cloneable調用clone()方法會拋出CloneNotSupportedException異常,源碼如下:
protected Object clone() throws CloneNotSupportedException {
if (!(this instanceof Cloneable)) {
throw new CloneNotSupportedException("Class " + getClass().getName() +
" doesn't implement Cloneable");
}
return internalClone();
}
/*
* Native helper method for cloning.
*/
private native Object internalClone();
在上一節中講了java中Serializable與Parcelable的使用序列化與反序列化的問題。事實上利用對象輸出流對對象進行序列化,利用對象的輸入流對對象進行反序列化也可以實現克隆,如果對象中依賴的其他對象的引用也實現了序列化(即引用類實現了serializable標記接口)就實現了深度克隆,否則實現了淺克隆.
實現了Serializable接口的Company
public class Company implements Serializable {//Serializable接口是空的,沒有聲明的方法及常量
private static final long serialVersionUID = 1L; //序列化標識
private String name;
private String address;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public Company(String name, String address) {
this.name = name;
this.address = address;
}
@Override
public String toString() {
return "company name is:"+name+",address is:"+address;
}
}
獲得實現了Serializable接口的克隆實例調用方法。
private T getCopyObj(T t) {
ByteArrayOutputStream byteArrayOutputStream = null;
ObjectOutputStream objectOutputStream = null;
ByteArrayInputStream byteArrayInputStream = null;
ObjectInputStream objectInputStream = null;
try {
byteArrayOutputStream = new ByteArrayOutputStream();
objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(t);//序列化對象
objectOutputStream.flush();
byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
objectInputStream = new ObjectInputStream(byteArrayInputStream);
T t1 = (T) objectInputStream.readObject();
return t1;
} catch (Exception e) {
e.printStackTrace();
} finally {
if (byteArrayOutputStream != null) {
try {
byteArrayOutputStream.close();
byteArrayOutputStream = null;
} catch (IOException e) {
e.printStackTrace();
}
}
if (objectOutputStream != null) {
try {
objectOutputStream.close();
objectOutputStream = null;
} catch (IOException e) {
e.printStackTrace();
}
}
if (byteArrayInputStream != null) {
try {
byteArrayInputStream.close();
byteArrayInputStream = null;
} catch (IOException e) {
e.printStackTrace();
}
}
if (objectInputStream != null) {
try {
objectInputStream.close();
objectInputStream = null;
} catch (IOException e) {
e.printStackTrace();
}
}
}
return null;
}
}
測試通過的testCase,說明通過Serializable的反序列化創建的是一個新的對象,不再是之前的對象了。
@Test
public void test() throws CloneNotSupportedException {
Company company=new Company("百度","上地十街");
Company copyCompany=getCopyObj(company);
copyCompany.setName("騰訊");
Assert.assertEquals(false,company==copyCompany);
Assert.assertEquals(true,company.getName().equals("百度"));
Assert.assertEquals(true,copyCompany.getName().equals("騰訊"));
}
實現了Clonable克隆的例子
public class People implements Cloneable {
private String name;
private int age;
public People(String name, int age) {
this.name = name;
this.age = age;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
驗證通過的case,表明了克隆出來的對象與原來的對象地址不一樣,是一個新的對象,所以克隆對象中的name和age是新的.
@Test
public void test() throws CloneNotSupportedException {
People people = new People("storm", 30);
People clonePeople = (People) people.clone();
clonePeople.setName("stormClone");
clonePeople.setAge(29);
Assert.assertFalse(people == clonePeople);
System.out.println("people name=" + people.getName());//people name=storm
System.out.println("people age=" + people.getAge());//people age=30
System.out.println("clonePeople name=" + clonePeople.getName());//clonePeople name=stormClone
System.out.println("clonePeople age=" + clonePeople.getAge());//clonePeople age=29
}
使用cloneable實現淺克隆
public class Animal {
private String animalName;
public Animal(String animalName) {
this.animalName = animalName;
}
public String getAnimalName() {
return animalName;
}
public void setAnimalName(String animalName) {
this.animalName = animalName;
}
}
public class People implements Cloneable {
private String name;
private int age;
private Animal animal;//克隆對象中的引用型變量
public People(String name, int age,Animal animal) {
this.name = name;
this.age = age;
this.animal=animal;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Animal getAnimal() {
return animal;
}
public void setAnimal(Animal animal) {
this.animal = animal;
}
}
驗證通過的case,表明了克隆對象的引用型變量animal并未發生改變,也即使內存中的地址并未發生改變,所以對其name的更改會影響原對象與克隆對象的值.
@Test
public void test() throws CloneNotSupportedException {
Animal animal=new Animal("cat");
People people = new People("storm", 30,animal);
People clonePeople = (People) people.clone();
animal.setAnimalName("dog");
Assert.assertFalse(people == clonePeople);
Assert.assertTrue(people.getAnimal()==clonePeople.getAnimal());
Assert.assertTrue(people.getAnimal().getAnimalName().equals("dog"));
Assert.assertTrue(clonePeople.getAnimal().getAnimalName().equals("dog"));
}
使用cloneable實現深克隆(實現很簡單只需要引用類型變量實現cloneable接口即可),相比淺克隆,只需做如下修改.
public class Animal implements Cloneable{
private String animalName;
public Animal(String animalName) {
this.animalName = animalName;
}
public String getAnimalName() {
return animalName;
}
public void setAnimalName(String animalName) {
this.animalName = animalName;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
驗證通過的case,表明了克隆對象的引用型變量animal發生改變,也即內存中的地址發生改變,所以對其name的更改不會影響克隆對象的值.同時說明了進行深克隆會把所有的引用類型都實現cloneable接口,如果克隆對象中的引用類型變量比較多的話,這牽涉的工作量就會比較大了,這時我們考慮使用上面實現Serializable實現克隆的方式,缺點是反復進行IO操作,內存開銷大.
@Test
public void test() throws CloneNotSupportedException {
Animal animal=new Animal("cat");
People people = new People("storm", 30,animal);
People clonePeople = (People) people.clone();
Animal cloneAnimal=(Animal) animal.clone();
clonePeople.setAnimal(cloneAnimal);
animal.setAnimalName("dog");
Assert.assertFalse(people == clonePeople);
Assert.assertFalse(people.getAnimal()==clonePeople.getAnimal());
Assert.assertTrue(people.getAnimal().getAnimalName().equals("dog"));
Assert.assertTrue(clonePeople.getAnimal().getAnimalName().equals("cat"));
}
總結
以上是生活随笔為你收集整理的java cloneable 用途_java中cloneable的使用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: android enum java包_A
- 下一篇: java获取被占用的文件进程_java