关于java:Java中的深浅拷贝问题你清楚吗

47次阅读

共计 2899 个字符,预计需要花费 8 分钟才能阅读完成。

一、前言

拷贝这个词想必大家都很相熟,在工作中常常须要拷贝一份文件作为正本。拷贝的益处也很显著,相较于新建来说,能够节俭很大的工作量。在 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 接口来标记,这个类反对拷贝。

为了演示不便,咱们新建两个实体类 DeptUser,其中User 依赖了Dept,实体类代码如下:

Dept

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Dept {

    private int deptNo;
    private String name;
}

User

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {

    private int age;
    private String name;
    private Dept dept;
}

二、浅拷贝

对于根本类型的的属性,浅拷贝会将属性值复制给新的对象,而对于援用类型的属性,浅拷贝会将援用复制给新的对象。而像 StringInteger 这些援用类型,都不是不可变的,拷贝的时候会创立一份新的内存空间来寄存值,并且将新的援用指向新的内存空间。不可变类型是非凡的援用类型,咱们权且认为这些 final 类型的利用也是复制值。

浅拷贝性能实现

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User implements Cloneable{

    private int age;
    private String name;
    private Dept dept;
    @Override
    protected Object clone() throws CloneNotSupportedException {return super.clone();
    }
}

如何验证咱们的论断呢?首先比照被拷贝出的对象和原对象是否相等,不等则阐明是新拷贝出的一个对象。其次批改拷贝出对象的根本类型属性,如果原对象的此属性产生了批改,则阐明根本类型的属性是同一个,最初批改拷贝出对象的援用类型对象即 Dept 属性,如果原对象的此属性产生了扭转,则阐明援用类型的属性是同一个。分明测试原理后,咱们写一段测试代码来验证咱们的论断。

public static void main(String[] args) throws Exception{Dept dept = new Dept(12, "市场部");
    User user = 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);
}

下面代码的运行后果如下

false

User{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
@NoArgsConstructor
public class Dept implements Cloneable {

    private int deptNo;
    private String name;

    @Override
    public Object clone() throws CloneNotSupportedException {return super.clone();
    }
}

user类:

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User implements Cloneable{

    private int age;
    private String name;
    private Dept dept;

    @Override
    protected Object clone() throws CloneNotSupportedException {User user = (User) super.clone();
        user.dept =(Dept) dept.clone();
        return user;
    }
}

应用浅拷贝的测试代码持续测试,运行后果如下:

false

User{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