java中cloneable的使用
来源:互联网 发布:开源股票软件 python 编辑:程序博客网 时间:2024/05/17 07:20
什么是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> 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")); }
阅读全文
0 0
- java中cloneable的使用
- Java中Cloneable 和 clone()的总结和使用
- Java中Cloneable接口的用法
- Java中Cloneable接口
- Java中Cloneable接口
- Java中Cloneable接口
- Java中Cloneable接口
- java中Cloneable接口
- Java中Cloneable接口
- Java HashTable的Cloneable实现
- java的Cloneable、Serializable接口
- Java Cloneable
- java中Cloneable与Serializable接口
- Java中Serializable接口和Cloneable接口
- Java中 Cloneable 、Serializable 接口详解
- java cloneable接口及使用场景
- Cloneable 和 clone()的总结和使用
- Cloneable 和 clone()的总结和使用
- 656
- html2canvas根据DOM元素样式实现网页截图
- Android---Gradle 多渠道打包
- intellij idea下使用Maven搭建SpringMVC
- Postgresql小特性:为nosuper用户预留连接数
- java中cloneable的使用
- 简述USB枚举过程
- js和php数字位数格式化自动补0
- NSLocalizedString和NSLocalizedStringFromTable的用法
- SessionStateMode之Redis共享session
- 排序
- BZOJ 2225: [Spoj 2371]Another Longest Increasing CDQ
- PL0源码分析之占位
- <s:iterator>标签的使用