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”));
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/181903.html原文链接:https://javaforall.cn
相关文章
- 大数据必学Java基础(五十六):LinkedList实现类的使用
- fileinputstream java_Java FileInputStream close()方法
- java用正则表达式大全_Java 正则表达式 大全「建议收藏」
- java session id 生成_Java通过sessionId获取Session「建议收藏」
- java如何输入字符串_JAVA中怎样输入字符串「建议收藏」
- java平均的随机数_Java 随机数详解「建议收藏」
- Java转换流_java中的字符使用什么编码
- java 文件上传到服务器_Java上传文件到服务器端的方法「建议收藏」
- java 异或加密_使用异或实现一个简单的加密或解密
- java 异或加密_Java异或技操作给任意的文件加密原理及使用详解
- java查找字符的方法_Java字符串查找(3种方法)
- java 数字信封_【Java密码学】使用Bouncy Castle生成数字签名、数字信封
- java prototype是什么,Java设计模式之原型模式(Prototype模式)介绍
- Java使用Lombok详解
- 【Binder 机制】AIDL 分析 ( 创建 AIDL 文件 | 创建 Parcelable 类 | AIDL 中使用 Parcelable 类 | 编译工程生成 AIDL 对应的Java源文件 )
- 浅谈Java中的hashcode方法详解编程语言
- 处理Java使用Redis实现过期时间处理(redisjava过期)
- 检测使用Redis与Java实现过期对象检测(redisjava过期)
- 如何在Linux系统下有效地启动Java程序,让你的代码在Linux中也能正常运行?(linux下启动java)
- 使用Java监听MySQL数据库变化(java监听mysql)
- Java数据库之MySQL学习使用教程(mysql中java教程)
- 使用Java语言写Redis实现一个分布式缓存系统(用java写个redis)
- 编程Oracle数据库中实现Java编程的突破之道(oracle使用java)
- Redis中使用Java快速实现自增(redis自增 java)
- [JAVA]十四种Java开发工具点评
- Java中使用内存映射实现大文件上传实例