一、前言

拷贝这个词想必大家都很相熟,在工作中常常须要拷贝一份文件作为正本。拷贝的益处也很显著,相较于新建来说,能够节俭很大的工作量。在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@NoArgsConstructorpublic class Dept {    private int deptNo;    private String name;}

User

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

二、浅拷贝

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

浅拷贝性能实现

@Data@AllArgsConstructor@NoArgsConstructorpublic 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);}

下面代码的运行后果如下

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;    private String name;    @Override    public Object clone() throws CloneNotSupportedException {        return super.clone();    }}

user类:

@Data@AllArgsConstructor@NoArgsConstructorpublic 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;    }}

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

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相干的面试题。