共计 2899 个字符,预计需要花费 8 分钟才能阅读完成。
一、前言
拷贝这个词想必大家都很相熟,在工作中常常须要拷贝一份文件作为正本。拷贝的益处也很显著,相较于新建来说,能够节俭很大的工作量。在 Java 中,同样存在拷贝这个概念,拷贝的意义也是能够节俭创建对象的开销。
Object
类中有一个办法clone()
,具体方法如下:
protected native Object clone() throws CloneNotSupportedException;
- 该办法由
protected
润饰,java 中所有类默认是继承Object
类的,重载后的clone()
办法为了保障其余类都能够失常调用,修饰符须要改成public
。 - 该办法是一个
native
办法,被native
润饰的办法实际上是由非 Java 代码实现的,效率要高于一般的 java 办法。 - 该办法的返回值是
Object
对象,因而咱们须要强转成咱们须要的类型。 - 该办法抛出了一个
CloneNotSupportedException
异样,意思就是不反对拷贝,须要咱们实现Cloneable
接口来标记,这个类反对拷贝。
为了演示不便,咱们新建两个实体类 Dept
和 User
,其中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;
}
二、浅拷贝
对于根本类型的的属性,浅拷贝会将属性值复制给新的对象,而对于援用类型的属性,浅拷贝会将援用复制给新的对象。而像 String
,Integer
这些援用类型,都不是不可变的,拷贝的时候会创立一份新的内存空间来寄存值,并且将新的援用指向新的内存空间。不可变类型是非凡的援用类型,咱们权且认为这些 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 相干的面试题。