AI智能
改变未来

Java中的深浅拷贝问题,你清楚吗?


一、前言

拷贝这个词想必大家都很熟悉,在工作中经常需要拷贝一份文件作为副本。拷贝的好处也很明显,相较于新建来说,可以节省很大的工作量。在Java中,同样存在拷贝这个概念,拷贝的意义也是可以节省创建对象的开销。

Object

类中有一个方法

clone()

,具体方法如下:

protected native Object clone() throws CloneNotSupportedException;
  1. 该方法由
    protected

    修饰,java中所有类默认是继承

    Object

    类的,重载后的

    clone()

    方法为了保证其他类都可以正常调用,修饰符需要改成

    public

  2. 该方法是一个
    native

    方法,被

    native

    修饰的方法实际上是由非Java代码实现的,效率要高于普通的java方法。

  3. 该方法的返回值是
    Object

    对象,因此我们需要强转成我们需要的类型。

  4. 该方法抛出了一个
    CloneNotSupportedException

    异常,意思就是不支持拷贝,需要我们实现

    Cloneable

    接口来标记,这个类支持拷贝。

为了演示方便,我们新建两个实体类

Dept

User

,其中

User

依赖了

Dept

,实体类代码如下:

Dept

@Data@AllArgsConstructor@NoArgsConstructorpublic class Dept {private int deptNo;private String name;}

User

@Data@AllArgsConstructor@NoArgsConstructorpublic class User {private int age;private String name;private Dept dept;}

二、浅拷贝

对于基本类型的的属性,浅拷贝会将属性值复制给新的对象,而对于引用类型的属性,浅拷贝会将引用复制给新的对象。而像

String

Integer

这些引用类型,都不是不可变的,拷贝的时候会创建一份新的内存空间来存放值,并且将新的引用指向新的内存空间。不可变类型是特殊的引用类型,我们姑且认为这些

final

类型的应用也是复制值。

浅拷贝功能实现

@Data@AllArgsConstructor@NoArgsConstructorpublic class User implements Cloneable{private int age;private String name;private Dept dept;@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}}

如何验证我们的结论呢?首先对比被拷贝出的对象和原对象是否相等,不等则说明是新拷贝出的一个对象。其次修改拷贝出对象的基本类型属性,如果原对象的此属性发生了修改,则说明基本类型的属性是同一个,最后修改拷贝出对象的引用类型对象即

Dept

属性,如果原对象的此属性发生了改变,则说明引用类型的属性是同一个。清楚测试原理后,我们写一段测试代码来验证我们的结论。

public static void main(String[] args) throws Exception{Dept dept = new Dept(12, \"市场部\");User user56c= new User(18, \"Java旅途\", dept);User user1 = (User)user.clone();System.out.println(user == user1);System.out.println();user1.setAge(20);System.out.println(user);System.out.println(user1);System.out.println();dept.setName(\"研发部\");System.out.println(user);System.out.println(user1);}

上面代码的运行结果如下

falseUser{age=18, name=\'Java\', dept=Dept{deptNo=12, name=\'市场部\'}}User{age=20, name=\'Java\', dept=Dept{deptNo=12, name=\'市场部\'}}User{age=18, name=\'Java\', dept=Dept{deptNo=12, name=\'研发部\'}}User{age=20, name=\'Java\', dept=Dept{deptNo=12, name=\'研发部\'}}

三、深拷贝

相较于浅拷贝而言,深拷贝除了会将基本类型的属性复制外,还会将引用类型的属性也会复制。

深拷贝功能实现

在拷贝

user

的时候,同时将

user

中的

dept

属性进行拷贝。

dept

类:

@Data@AllArgsConstructor@NoArgsConstructorpublic class Dept implements Cloneable {private int deptNo;prad8ivate String name;@Overridepublic Object clone() throws CloneNotSupportedException {return super.clone();}}

user

类:

@Data@AllArgsConstructor@NoArgsConstructorpublic class User implements Cloneable{private int age;private String name;private Dept dept;@Overrideprotected Object clone() throws CloneNotSupportedException {User user = (User) super.clone();user.dept =(Dept) dept.clone();return user;}}

使用浅拷贝的测试代码继续测试,运行结果如下:

falseUser{age=18, name=\'Java旅途\', dept=Dept{deptNo=12, name=\'市场部\'}}User{age=20, name=\'Java旅途\', dept=Dept{deptNo=12, name=\'市场部\'}}User{age=18, name=\'Java旅途\', dept=Dept{deptNo=12, name=\'研发部\'}}User{age=20, name=\'Java旅途\', dept=Dept{deptNo=12, name=\'市场部\'}}

除此之外,还可以利用反序列化实现深拷贝,先将对象序列化成字节流,然后再将字节流序列化成对象,这样就会产生一个新的对象。

参考:再见:深拷贝、浅拷贝问题!——CodeSheep

点关注、不迷路

如果觉得文章不错,欢迎关注、点赞、收藏,你们的支持是我创作的动力,感谢大家。

如果文章写的有问题,请不要吝惜文笔,欢迎留言指出,我会及时核查修改。

如果你还想看到更多别的东西,可以微信搜索「Java旅途」进行关注。「Java旅途」目前已经整理各种中间件的使用教程及各类Java相关的面试题。扫描下方二维码进行关注就可以得到这些资料。

赞(0) 打赏
未经允许不得转载:爱站程序员基地 » Java中的深浅拷贝问题,你清楚吗?