目录
文章目录
前言
1) 引用拷贝
2) 对象拷贝
二 . 浅拷贝
1) 拷贝构造方法实现浅拷贝
2) 工厂方法实现浅拷贝
3) clone方法实现浅拷贝
三 . 深拷贝
1) 通过重写clone方法来实现深拷贝
2) 通过对象序列化实现深拷贝
大家好,今天给大家带来的是java中的深浅拷贝
一 . 拷贝的引入
引用拷贝通常指的是浅拷贝,即只复制了对象本身,而没有复制对象内部的引用对象。这意味着原始对象和拷贝对象仍然共享相同的引用对象
创建一个指向对象的引用变量的拷贝对象
Student s1 = new Student("张三",23); Student s2 = s1; System.out.println(s1); System.out.println(s2);
创建对象本身的一个副本。
Student student = new Student("张三",23); Student otherStudent = (Student)student.clone(); System.out.println(student); System.out.println(otherStudent);
结果分析:由输出结果可以看出,它们的地址是不同的,也就是说创建了新的对象, 而不是把原对象的地址赋给了一个新的引用变量,这就叫做对象拷贝。
Java中的对象拷贝(Object Copy)指的是将一个对象的所有属性(成员变量)拷贝到另一个有着相同类类型的对象中去。
在程序中拷贝对象是很常见的,主要是为了在新的上下文环境中复用现有对象的部分或全部 数据。
Java中的对象拷贝主要分为:浅拷贝(Shallow Copy)、深拷贝(Deep Copy)。
浅拷贝是指在拷贝对象时,只复制对象本身,而不复制对象内部的引用对象。这意味着原始对象和拷贝对象会共享相同的引用对象,如果引用对象发生改变,原始对象和拷贝对象都会受到影响。
①对于数据类型是基本数据类型的成员变量,浅拷贝会直接进行值传递,也就是将该属性值复制一份给新的对象。因为是两份不同的数据,所以对其中一个对象的该成员变量值进行修改,不会影响另一个对象拷贝得到的数据。
②对于数据类型是引用数据类型的成员变量,比如说成员变量是某个数组、某个类的对象等,那么浅拷贝会进行引用传递,也就是只是将该成员变量的引用值(内存地址)复制一份给新的对象。因为实际上两个对象的该成员变量都指向同一个实例。
在这种情况下,在一个对象中修改该成员变量会影响到另一个对象的该成员变量值。
浅拷贝的实现方式主要有三种
class Person {
Age age;
String name;
public Person(Age age, String name) {
this.age = age;
this.name = name;
}
/**
* 拷贝构造方法
* @param p
*/
public Person(Person p){
this.age = p.age;
this.name = p.name;
}
}
class Age{
int age;
public Age(int age) {
this.age = age;
}
}
Age age = new Age(18); Person person1 = new Person(age,"张三"); Person person2 = new Person(person1); System.out.println(person1); System.out.println(person2);
改变一个方法就行,其他的不变
/**
* 工厂方法
* @param p
*/
public Person clone(Person p){
return new Person(p.age,p.name);
}
Object类是类结构的根类,其中有一个方法为protected Object clone() throws CloneNotSupportedException,这个方法就是进行的浅拷贝。有了这个浅拷贝模板,我们可以通过调用clone()方法来实现对象的浅拷贝。
但是需要注意:
1、Object类虽然有这个方法,但是这个方法是受保护的(被protected修饰),所以我们无法直接使用。
2、使用clone方法的类必须实现Cloneable接口,否则会抛出异常CloneNotSupportedException。
对于这两点,我们的解决方法是,在要使用clone方法的类中重写clone()方法,通过super.clone()调用Object类中的原clone方法
public class ShallowCopy {
public static void main(String[] args) throws CloneNotSupportedException {
Age age = new Age(18);
Person person1 = new Person(age,"张三");
Person person2 = (Person)person1.clone();
System.out.println(person1);
System.out.println(person2);
}
}
class Person implements Cloneable{
Age age;
String name;
public Person(Age age, String name) {
this.age = age;
this.name = name;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
class Age{
int age;
public Age(int age) {
this.age = age;
}
}
深拷贝指的是在复制对象时,不仅复制了对象本身,还复制了对象内部的所有引用对象,使得原始对象和拷贝对象完全独立,彼此不会相互影响。
在进行深拷贝时,需要递归地复制对象及其内部的所有引用对象,确保每个对象都是独立的
浅拷贝示意图
深拷贝示意图
如果Age对象依然关联其他引用对象,同样也是需要拷贝的
深拷贝的实现方法主要有两种
class Animal implements Cloneable{
int age;
String name;
Dog dog;
public Animal(int age, String name, Dog dog) {
this.age = age;
this.name = name;
this.dog = dog;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Dog getDog() {
return dog;
}
public void setDog(Dog dog) {
this.dog = dog;
}
@Override
protected Object clone() throws CloneNotSupportedException {
Animal animal = (Animal)super.clone();
animal.setDog((Dog)animal.getDog().clone());
return animal;
}
}
class Dog implements Cloneable{
int age;
String name;
public Dog(int age, String name) {
this.age = age;
this.name = name;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
Animal animal = new Animal(1,"小黄",new Dog(1,"小黄")); Animal cloneAnimal = (Animal) animal.clone(); System.out.println(animal); System.out.println(cloneAnimal); System.out.println(animal.getDog()); System.out.println(cloneAnimal.getDog());
结果分析 : 两个引用animal和cloneAnimal指向不同的两个对象,两个引用animal和cloneAnimal中的两个Dog引用指向的是两个对象,但对Dog对象的修改只能影响animal对象,所以说是深拷贝。
虽然层次调用clone方法可以实现深拷贝,但是显然代码量实在太大。特别对于属性数量比较多、层次比较深的类而言,每个类都要重写clone方法太过繁琐。
将对象序列化为字节序列后,默认会将该对象的整个对象图进行序列化,再通过反序列即可完美地实现深拷贝。
参考代码如下
import java.io.*;
class MyClass implements Serializable {
int number;
public MyClass(int number) {
this.number = number;
}
}
public class DeepCopyExample {
public static void main(String[] args) {
// 创建一个原始对象
MyClass originalObject = new MyClass(10);
// 使用序列化和反序列化进行深拷贝
MyClass copiedObject = deepCopy(originalObject);
// 修改原始对象的值
originalObject.number = 20;
// 打印拷贝对象的值,验证是否进行了深拷贝
System.out.println(copiedObject.number); // 输出 10
}
// 使用序列化和反序列化进行深拷贝
public static T deepCopy(T object) {
try {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ObjectOutputStream output = new ObjectOutputStream(outputStream);
output.writeObject(object);
ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
ObjectInputStream input = new ObjectInputStream(inputStream);
return (T) input.readObject();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
总结
这篇文章这要给大家介绍了一下java中的深浅拷贝,我们下一篇博客见