对于java拷贝的理解
在java语言,当我们需要拷贝一个Java对象的时候,常见的会有两种方式拷贝:浅拷贝和深拷贝。浅拷贝只是拷贝了源对象的地址,所以源对象的任何值发生改变的时候,拷贝对象的值就会随之发生变化。但是深拷贝则是拷贝了源对象的所有值而不是地址,所以即使源对象的值发生了任何变化,拷贝对象的值也不会有变化。

浅拷贝
具体可以生成如下的实体和测试类:
User类:
public class User {
private String username;
private String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
ClmTest测试类:
public class ClmTest {
public static void main(String[] args) {
//首先我们先创建一个User对象
User userAm = new User();
userAm.setUsername("HerculesZhang");
userAm.setPassword("123456");
//浅拷贝
User userBm = userAm;
//当我们进行浅拷贝的时候,对象的地址是一样的,我们可以把对象打印出来验证
System.out.println("userAm="+userAm);
System.out.println("userBm="+userBm);
}
}
打印结果如下:

那么浅拷贝具有的问题是什么呢。浅拷贝的问题就是当其中一个对象的某个属性改变时,其他对象的属性都要改变。比如我们打印一下两个对象的username属性:
public class ClmTest {
public static void main(String[] args) {
//首先我们先创建一个User对象
User userAm = new User();
userAm.setUsername("HerculesZhang");
userAm.setPassword("123456");
//浅拷贝
User userBm = userAm;
//当我们进行浅拷贝的时候,对象的地址是一样的,我们可以把对象打印出来验证
System.out.println("userAm="+userAm);
System.out.println("userBm="+userBm);
System.out.println(userAm.getUsername());
System.out.println(userBm.getUsername());
}
}
可以看到如下结果:

这时候我们可以改变一下Bm的属性:
public class ClmTest {
public static void main(String[] args) {
//首先我们先创建一个User对象
User userAm = new User();
userAm.setUsername("HerculesZhang");
userAm.setPassword("123456");
//浅拷贝
User userBm = userAm;
//当我们进行浅拷贝的时候,对象的地址是一样的,我们可以把对象打印出来验证
System.out.println("userAm="+userAm);
System.out.println("userBm="+userBm);
System.out.println(userAm.getUsername());
System.out.println(userBm.getUsername());
userBm.setUsername("hercule");
System.out.println(userAm.getUsername());
System.out.println(userBm.getUsername());
}
}
再看一下输出结果:

可以看到两个对象的地址是一样的,开始的时候我们并没有调用BM的set方法,只调用了Am的但是这时候Am和Bm还是一样的。我们再调用Bm的set方法Am的值也改变了,可以看到浅拷贝拷贝的只是对象的地址。
深拷贝

对于深拷贝来说就是对于一个对象属性的改变并不会引起另一个拷贝对象或者被拷贝对象属性的变化。
常见的几种深拷贝方式:
1、构造函数方式
2、重写clone方法
3、Apache Commons Lang序列化
4、Gson序列化
5、Jackson序列化
这篇文章我们先讲解前两种深拷贝的方式
1、构造函数的深拷贝
我们所需要做的就是首先在bean对象中添加有参的构造函数
public User(String username, String password) {
this.username = username;
this.password = password;
}
而后再创建对象的时候,通过new的方式来完成
User user1 = new User("name1","123456");
User user2 = new User("name2","123456");
new的方式可以让每一个对象都是新创建的,它们之间互不干扰,但是new的方式在对象个数和很少的情况下,勉强能够使用,在创建对象过多的时候,对于系统的开销很大,所以并不推荐用这种方式完成。
而后我们将实体代码修改如下:
User:
public class User {
private String username;
private String password;
public User() {
}
public User(String username, String password) {
this.username = username;
this.password = password;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
而后测试类修改:
public class Test2 {
public static void main(String[] args) {
//首先我们先创建一个User对象
User userAm = new User("HerculesZhang","123456");
User userBm = new User("hercule","123456");
System.out.println("userAm"+userAm);
System.out.println("userBm"+userBm);
}
}
输出一下:

打印结果可见这两个对象的地址是不一致的。在java世界中地址不一样,那么数据就是隔离的。
那么我们再改一下测试类:
public class Test2 {
public static void main(String[] args) {
//首先我们先创建一个User对象
User userAm = new User("HerculesZhang","123456");
User userBm = new User("hercule","123456");
System.out.println("userAm"+userAm);
System.out.println("userBm"+userBm);
//这时我们修改一下Am的name属性
userAm.setUsername("HerculesAm");
System.out.println("userAm getUsername--"+userAm.getUsername());
System.out.println("userBm getUsername--"+userBm.getUsername());
}
}
打印结果如下:

上面我们只是以构造函数的形式初步了解了一下深拷贝,这种方法是我们刚学java的时候喜欢用到的方法。
2、重写clone方法
1、对于重写clone方法我们需要做的就是重写Object继承而来的clone()方法,并且修改为public
public class User implements Cloneable
2、实现Cloneable接口来告诉JVM此类允许拷贝
public User clone() throws CloneNotSupportedException{
return (User)super.clone();
}
我感觉还是以代码的方式说明比较直观:
首先实体修改如下:
public class User implements Cloneable{
private String username;
private String password;
public User() {
}
public User(String username, String password) {
this.username = username;
this.password = password;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public User clone() throws CloneNotSupportedException {
return (User) super.clone();
}
}
测试类如下:
public class Test3 {
public static void main(String[] args) {
//首先我们先创建一个User对象
try {
User userAm = new User("HerculesZhang","123456");
User userBm = userAm.clone();
System.out.println("userAm="+userAm);
System.out.println("userBm="+userBm);
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
}
输出结果:
这里可以明显的看到两个对象的地址是不同的

这时候我们再来打印一下每个对象的username
System.out.println("userAm--username--"+userAm.getUsername());
System.out.println("userBm--username--"+userBm.getUsername());

而后我们给Bm的username单独重新赋值
userBm.setUsername("HerBm");
System.out.println("userAm--username--"+userAm.getUsername());
System.out.println("userBm--username--"+userBm.getUsername());

可以看到我们操作了Bm的username以后并没有影响到Am的值。
但是这里这种情况如果我们用这个克隆方法,那么他只是适合属性是基本数据类型的,如果这里实体中的属性是对象则不适合。需要进一步改造才能够支持属性是对象的克隆。
551

被折叠的 条评论
为什么被折叠?



