-
2022-02-07 09:47:39
关于对象的克隆,Java自带了一个clone()方法。
但是众所周知,这个clone()方法只是做浅层的对象复制,仅适用于对象属性是简单数据类型(int/long/float等)的场景。对于对象属性是对象的情况,就不适用。于是就有深度克隆对象场景。
深度克隆对象的总思路就是编码化再反编码,如下面的例子,就是将对象编码化是Bytes,然后再由Bytes反编码回对象。
public Object deepClone(){ // 1.将对象写到流里 ByteArrayOutoutStream bo=new ByteArrayOutputStream(); ObjectOutputStream oo=new ObjectOutputStream(bo); oo.writeObject(this); // 2.从流里读出来 ByteArrayInputStream bi=new ByteArrayInputStream(bo.toByteArray()); ObjectInputStream oi=new ObjectInputStream(bi); return(oi.readObject()); }
当然,除了编码为Bytes外,还是编码为Json等再反编码,两者主要区别在于性能(有兴趣的童鞋可以测试下)。
除了编码反编码外,还能通过反射的方式来克隆对象,个人感觉该方式性能不高(暂时未通过实践验证),就不展开介绍,详情可以查看《Java从入门到精通(第6版)》第16章 反射与注解。
最后一种方法,就是硬克隆,手动写代码,每个对象属性递归拷贝,可能是萌新最常用的方法。
更多相关内容 -
Java对象深克隆的两种方式
2021-02-13 02:29:00# clone的条件如果你想clone一个对象,就必须满足两个条件:1. 你必须实现Cloneable接口(用于标识该对象可被clone,空接口)2....深克隆即clone对象本体。# 实现深克隆的方式1. 先使用待克隆对象的clone方...# clone的条件
如果你想clone一个对象,就必须满足两个条件:
1. 你必须实现Cloneable接口(用于标识该对象可被clone,空接口)
2. 必须覆盖Object的clone方法
clone分为浅克隆和深克隆。Object对象的clone方法是浅克隆,即待克隆的对象若存在对象实例域,则仅仅clone其引用。深克隆即clone对象本体。
# 实现深克隆的方式
1. 先使用待克隆对象的clone方法,再调用对象实例域的clone方法并将结果覆盖引用类型。(待克隆对象和其对象实例域必须实现Cloneable接口并覆盖clone方法)
2. 使用对象序列化clone。(克隆对象和其对象实例域必须实现Serializable接口)
```
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
/**
* ------------对象克隆测试---------------
*
* Object的clone方法是浅克隆,即待克隆的类实例域中存在对象时,仅仅clone其引用。
* 一个对象想要被克隆要满足两个条件:
* 1. 实现Cloneable接口,虽然是空接口,但表明该对象可以被clone
* 2. 覆盖Object的clone方法
*
* 深克隆的方式:
* 1. 使用实例域对象的clone方法clone自身。对于待克隆对象A的对象实例域B也实现Cloneable接口,并覆盖clone方法。
* 先调用A的clone方法clone自身,再调用B的clone方法克隆它自身并将该值覆盖A
* 对象的B实例域。
* 2. 使用序列化来clone对象A中的对象实例域。但是这种方式代价太高,因为序列化很慢并且不安全。
*
* @author xl
*
*/
public class ObjectClone {
public static void main(String[] args) {
Person p1 = new Person("Alice", true, (byte)12, new Student("001"));
System.out.println(p1);
try {
Person p2 = (Person) p1.clone();
System.out.println(p2);
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
}
class Person implements Cloneable, Serializable {
/**
*
*/
private static final long serialVersionUID = -5773931460922468711L;
protected String name;
boolean sex;
byte age;
Student s;
public Person(String name, boolean sex, byte age, Student s) {
super();
this.name = name;
this.sex = sex;
this.age = age;
this.s = s;
}
深克隆1:调用对象实例域的clone方法。待克隆对象和其对象字段必须实现Cloneable接口
//@Override
//protected Object clone() throws CloneNotSupportedException {
//Person person = (Person)super.clone();
//person.s = (Student) this.s.clone();
//return person;
//}
//深克隆2:使用对象序列clone。待克隆对象的对象字段必须实现Serializable接口
@Override
protected Object clone() throws CloneNotSupportedException {
Person person = null;
try (
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
) {
//将待克隆对象序列化
oos.writeObject(this);
try (ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()));) {
//反序列化待克隆对象并在内存中重建
person = (Person)ois.readObject();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
return person;
}
@Override
public String toString() {
return "Person [name=" + name + ", sex=" + sex + ", age=" + age + ", s=" + s + "]";
}
}
class Student implements Cloneable, Serializable {
/**
*
*/
private static final long serialVersionUID = 2741427318104578724L;
String id = "001";
public Student(String id) {
this.id = id;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
```
>环境:
java version "1.8.0_111"
Java(TM) SE Runtime Environment (build 1.8.0_111-b14)
Java HotSpot(TM) Client VM (build 25.111-b14, mixed mode)
-
深入JAVA对象深度克隆的详解
2020-09-05 08:53:06本篇文章是对JAVA对象深度克隆进行了详细的分析介绍,需要的朋友参考下 -
java 对象的克隆(浅克隆和深克隆)
2020-08-29 22:17:55主要介绍了java 对象的克隆的相关资料,这里对浅克隆和深克隆进行了实例分析需要的朋友可以参考下 -
Java深克隆实现方法
2021-12-28 15:16:53Java的Object类中有个clone()方法,我们都知道想要克隆一个对象,只需要实现Cloneable这个标记接口并重写clone()方法即可,但是令人烦恼的是,这个Object类中的clone()方法只能实现浅克隆,即只能将基本类型的值进行...引入
Java的Object类中有个clone()方法,我们都知道想要克隆一个对象,只需要实现Cloneable这个标记接口并重写clone()方法即可,但是令人烦恼的是,这个Object类中的clone()方法只能实现浅克隆,即只能将基本类型的值进行复制和引用类型的地址进行复制,没办法将引用类型指向的真正对象进行复制。,这样就导致原来对象和克隆出来的对象共享引用对象,假如一个对象里修改了引用对象,另外一个对象也将会受到影响。
而我们希望的是引用对象也被复制一份,就不用共享了
分析
既然知道了浅克隆的原理,那么实现深克隆就迎刃而解了,我们只需要将引用对象也克隆下来就行了,那么Java中有哪些引用类型呢?处了8大基本类型外,String,类,数组都是引用类型。
因此在需要实现深克隆的地方要注意要克隆的对象的属性里面是否存在这些引用类型。实现方式1
前面说了可以重写Object类中的clone()方法能实现浅克隆,但其实也能实现深克隆,只是要在clone()方法的重写中加入自己的实现逻辑。
浅克隆
Room类:
public class Room implements Cloneable{ Desk desk; @Override protected Room clone() throws CloneNotSupportedException { return (Room) super.clone();//直接调用Object中的clone() } //隐藏了构造方法和getter setter }
Desk类:
public class Desk { String shape; public Desk(String shape) { this.shape = shape; } }
调用clone()方法:
public static void main(String[] args) throws CloneNotSupportedException { Room room = new Room(new Desk("圆桌")); Room cloneRoom = room.clone(); System.out.println(room == cloneRoom); System.out.println(room.desk == cloneRoom.desk); }
结果:说明desk是共享的
深克隆
既然直接调用Object类中的clone没法实现深克隆,那么就需要加入自己的实现逻辑了,有两种方法:
方式1
修改Room类的clone方法
@Override protected Room clone() throws CloneNotSupportedException { Room cloneRoom = (Room) super.clone(); Desk desk = new Desk(); desk.setShape(cloneRoom.desk.getShape()); cloneRoom.setDesk(desk); return cloneRoom; }
结果:
表面上看这种实现没有问题,因为确实实现了深克隆,但是细想一下,克隆的时候Desk对象是我们new出来的,而且desk对象的属性也是我们从原来的desk对象中获取然后通过set方法进行注入的,加入desk对象中有十个、一百个属性那我们是不是要用一大堆代码去获取注入呢?这显然是不符合实际情况的。因此来看第二种方式。方式2
透过方式1我们可以发现,其实我们实现深克隆的目的就是将对象的引用类型的属性复制一份出来然后再替换原来的属性。既然是复制,那不就又回到了克隆问题上了吗?不就就一层一层的套娃吗?
Desk类:public class Desk implements Cloneable { String shape; public Desk(String shape) { this.shape = shape; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); }
修改Room中的clone方法:
@Override protected Room clone() throws CloneNotSupportedException { Room cloneRoom = (Room) super.clone(); Desk desk = (Desk) this.desk.clone();//克隆一个desk cloneRoom.setDesk(desk); return cloneRoom; }
结果:
问题:以上案例都是类类型的引用对象,那数组类型的引用对象该怎么克隆呢?
目前在Java中数据拷贝提供了如下方式:- clone()
- System.arraycopy()
- Arrays.copyOf()
- Arrays.copyOfRange()
实现方式2
第一种方式是通过重写Object类中的clone()方法实现的,接下来使用对象序列化来实现克隆。
**思路:**将对象序列化,然后马上反序列化回来
Room类:public class Room implements Serializable { Desk desk; public Room deepClone() throws Exception{ //序列化 ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream); objectOutputStream.writeObject(this); //反序列化 ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray()); ObjectInputStream objectInputStream = new ObjectInputStream(inputStream); Room roomClone = (Room)objectInputStream.readObject(); return roomClone; } //忽略构造方法 }
Desk类:
public class Desk implements Serializable { String shape; }
结果:
注意:使用序列化与反序列化时必须实现标记接口Serializable -
Java实现对象深度克隆
2021-03-07 15:44:56实现Serializable接口,通过对象的序列化和反序列化实现克隆,可以实现真正的深度克隆,代码如下 import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io....两种方式:
1). 实现Cloneable接口并重写Object类中的clone()方法;
2). 实现Serializable接口,通过对象的序列化和反序列化实现克隆,可以实现真正的深度克隆,代码如下import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; public class MyUtil { private MyUtil() { throw new AssertionError(); } @SuppressWarnings("unchecked") public static <T extends Serializable> T clone(T obj) throws Exception { ByteArrayOutputStream bout = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bout); oos.writeObject(obj); ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bin); return (T) ois.readObject(); // 说明:调用ByteArrayInputStream或ByteArrayOutputStream对象的close方法没有任何意义 // 这两个基于内存的流只要垃圾回收器清理对象就能够释放资源,这一点不同于对外部资源(如文件流)的释放 } }
class Student implements Cloneable{ private String name; private int age; private StudentClass studentClass; private List<String> list = new ArrayList<>(); public Student() { // TODO Auto-generated constructor stub System.out.println("构造方法被调用"); } 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 StudentClass getStudentClass() { return studentClass; } public void setStudentClass(StudentClass studentClass) { this.studentClass = studentClass; } public void add(String aa){ this.list.add(aa); } @Override public Object clone() throws CloneNotSupportedException { // TODO Auto-generated method stub Student stu = (Student) super.clone(); return stu; } @Override public String toString() { return "Student [name=" + name + ", age=" + age + ",class"+studentClass.getStudentClass()+",list"+list+"]"; } }
-
实例分析java对象中浅克隆和深克隆
2020-08-26 22:34:09在本篇文章中我们给大家分享了关于java对象中浅克隆和深克隆的相关知识点和相关代码内容,有兴趣的朋友们学习下。 -
java对象复制克隆
2013-10-28 08:52:09深度复制Java对象实例,复制后对象属性值改变不影响被复制对象,有注释 -
java 对象深拷贝工具
2021-02-12 23:16:16来自:http://www.cnblogs.com/DreamDrive/p/5430981.html需要对象实现Serializable接口public class CloneUtils {// 拷贝一个对象@SuppressWarnings("unchecked")public static T clone(T obj) {// 拷贝产生的对象T... -
Java实现深克隆的三种方式
2019-11-15 17:14:13大家都知道,Java中的克隆有深克隆和浅克隆,今天我们谈谈深克隆的几种实现方式。 首先,我们先谈谈浅克隆的实现 一、浅克隆 Java中实现浅克隆主要就是要实现Cloneable接口,然后返回克隆对象。 假设,现在我们... -
Java编程实现对象克隆(复制)代码详解
2020-08-28 17:13:18主要介绍了Java编程实现对象克隆(复制)代码详解,涉及了克隆的原因,如何实现克隆,克隆的一般步骤,深克隆与浅克隆的介绍等相关内容,具有一定借鉴价值,需要的朋友可以参考下。 -
java深度克隆
2012-05-29 09:10:19java深度克隆,可以复制对象,非常好用,谁用谁知道! -
java中实现对象的深度克隆
2018-08-03 10:08:25python中有深度拷贝(也可以叫深度克隆)和浅拷贝,同样在java中很多时候需要深度拷贝对象,所谓的深度拷贝对象指的就是对于对象的所用数据及其全部进行copy一份,变成两个完全不相关的对象,而浅拷贝不拷贝对象... -
Java深克隆和浅克隆
2021-05-02 13:11:01一般情况下,我们实际需要使用的是深克隆。 二、如何实现克隆 对象的类实现Cloneable接口; 重写Object类的clone()方法 ; 在clone()方法中调用super.clone(); 三、两种不同的克隆方法,浅克隆(Shal -
Java8之深克隆与浅克隆
2022-02-08 10:37:02克隆又分浅克隆与深克隆,他们的区别在于,对于引用类型的成员变量,浅克隆复制的是引用,而深克隆复制的是对象。 浅克隆(Shadow Clone)是把原型对象中成员变量为值类型的属性都复制给克隆对象,把原型对象中... -
Java中对象的深复制(深克隆)和浅复制(浅克隆)介绍
2020-09-03 21:05:18主要介绍了Java中对象的深复制(深克隆)和浅复制(浅克隆) ,需要的朋友可以参考下 -
Java对象克隆——浅克隆和深克隆的区别
2017-08-06 00:51:35在Java中对象的克隆有深克隆和浅克隆之分。有这种区分的原因是Java中分为基本数据类型和引用数据类型,对于不同的数据类型在内存中的存储的区域是不同的。基本数据类型存储在栈中,引用数据类型存储在堆中。 ... -
【Java基础】对象深克隆和浅克隆的原理及实现
2020-01-08 21:16:36彻底理解Java深克隆和浅克隆的原理及实现 Java 面试:对象克隆 如何拷贝对象 ...Java对象克隆——浅克隆和深克隆的区别 Java深克隆和浅克隆的原理及实现 为什么要对象克隆? 克隆的对象可能包含一... -
Java对象克隆
2021-03-08 03:24:41Java不提供克隆(复制)对象的自动机制。克隆对象意味着逐位复制对象的内容。要支持克隆操作,请在类中实现clone()方法。Object类中的clone()方法的声明如下:protected Object clone() throws ... -
JAVA中对象的克隆
2022-02-18 14:28:57对象克隆 Object类中定义一个clone方法 protected native Object clone() throws CloneNotSupportedException; native方法用于声明一个非java语言实现的代码,供java程序调用。因为java语言程序是运行在JVM上, ... -
Java中浅克隆和深克隆之异同
2021-02-26 14:39:25深克隆:创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址; 异同点: 深浅克隆都会在堆中新分配一块区域; 区别在于对象属性引用的对象是否需要进行克隆(递归性的)。 示例 pos:... -
Java实现对象克隆的方法
2021-03-01 09:35:23正文JAVA实现克隆有两种形式浅克隆深克隆浅克隆与深克隆的区别JAVA将数据类型分为基本数据类型以及引用数据类型,我认为浅克隆与深克隆的区别主要在于对引用类型的成员属性的操作。深度克隆应该递归克隆引用类型的... -
Java-对象克隆
2021-02-12 23:12:111. 为什么要克隆在java中,我们通过直接=等号赋值的方法来拷贝,如果是基本数据类型是没有问题的,例如int i = 1;int j = 0;j = i; // 直接=等号赋值,这样是没有问题的但是如果是引用数据类型,我们拷贝的就是引用... -
java深克隆对象
2021-07-05 14:55:54* 深克隆对象 */ public class CloneUtils { public static <T extends Serializable> T clone(T obj) { T cloneObj = null; try { // 写入字节流 ByteArrayOutputStream out = new ... -
java对象克隆
2021-02-28 12:46:471.浅拷贝可以直接调用Object的clone方法,来完成对象自身的克隆,这个方法只能拷贝各个类的域值,如果如果这个类的属性中包含的是一种引用,克隆对象和原对象的相同域会引用同一个引用对象。关于浅拷贝的子对象:... -
beancopy:java bean深度克隆的简单实现
2021-05-09 05:14:23beancopy ###java bean深度克隆的简单实现 Bean中必须有对应的getter, setter方法. 可以复制包含 "8种基本类型, String, java.util.Date, enum, Set, List 以及多层嵌套" 的Bean. -
2种方法实现java对象的深拷贝
2017-12-03 22:23:072.2、通过序列化方式实现深拷贝:先将要拷贝对象写入到内存中的字节流中,然后再从这个字节流中读出刚刚存储的信息,作为一个新对象返回,那么这个新对象和原对象就不存在任何地址上的共享,自然实现了深拷贝。...