引用拷贝和对象拷贝
(1)引用拷贝:将对象的引用赋值给引用类型的变量
Object obj = new Object();
Object obj1 = obj;
(2)对象拷贝
创建对象的一个副本,其中副本和源对象的引用是两个不同的地址,而不是把一个引用赋值给一个新的引用类型的变量
class Demo{
public static void main(String[] args) throws CloneNotSupportedException {
User user = new User();
User user1 = (User)user.clone();
System.out.println(user);
System.out.println(user1);
}
}
class User implements Cloneable {
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
浅拷贝和深拷贝都是对象拷贝
- 浅拷贝:源对象和拷贝对象的存放地址不同,但被复制的源对象的引用类型属性存放的地址仍然和源对象的引用类型属性相同,修改引用类型属性的属性会影响相互影响。
- 深拷贝:源对象和拷贝对象的存放地址不同,源对象和拷贝对象各自的引用类型存放的地址也和源对象的引用类型属性不同,修改引用类型属性的属性不会相互影响拷贝对象和源对象。
常见的浅拷贝方式
(1)一个引用类型变量直接赋值给另一个变量
(2)BeaUtil.copyProperties()
常见的深拷贝方式
(1)通过构造器或new的方式
(2)重写继承至Object方法的clone方法,并实现Cloneable接口
如果在没有实现Cloneable 接口的实例上调用 Object 的 clone 方法,则会导致抛出 CloneNotSupportedException 异常,实现Cloneable 接口的目的是:为了告知JVM,此对象允许拷贝
public class Main {
public static void main(String[] args) throws CloneNotSupportedException {
User user = new User(1, "测试");
User user1 = user.clone();
System.out.println(user1);
}
}
class User implements Cloneable{
private Integer id;
private String name;
//必须重写此方法
@Override
protected User clone() throws CloneNotSupportedException {
return (User)super.clone();
}
public User(Integer id, String name) {
this.id = id;
this.name = name;
}
}
注意: 当通过Cloneable接口实现深拷贝时,拷贝的源对象的属性如果是引用对象(String类型除外),则该属性也需要实现Cloneable接口,并覆写clone方法,否则该属性是进行的浅拷贝。
深拷贝特殊情况(String类型)
String类型属性:Clonable拷贝后两个对象的相同属性指向了通过字符串,但字符串是不可以修改的,存放在常量池中,当其中1个对象的该属性指向另个字符串时,另外一个对象的属性的引用仍指向原字符串。
public class ProtoTypeDemo {
public static void main(String[] args) throws CloneNotSupportedException {
Person person = new Person();
person.setId(1L);
person.setName("test");
User user = new User();
user.setUsername("测试");
person.setUser(user);
Person person1 = person.clone();
User user1 = user.clone();
user1.setUsername("cs");
person1.setUser(user1);
System.out.println(person1);//Person{id=1, name='test', user=User{username='cs'}}
System.out.println(person);//Person{id=1, name='test', user=User{username='测试'}}
}
}
public class Person implements Cloneable {
private Long id;
private String name;
private User user;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public Person clone() throws CloneNotSupportedException {
return (Person) super.clone();
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
@Override
public String toString() {
return "Person{" +
"id=" + id +
", name='" + name + '\'' +
", user=" + user +
'}';
}
}
public class User implements Cloneable{
private String username;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
@Override
public User clone() throws CloneNotSupportedException {
return (User) super.clone();
}
@Override
public String toString() {
return "User{" +
"username='" + username + '\'' +
'}';
}
}
(3)序列化的方式:FastJson、Gson等都可以
class Main{
public static void main(String[] args) {
User user = new User(1, "测试");
//序列化
String s = JSONObject.toJSONString(user);
//反序列化
System.out.println(s);
User user1 = JSON.parseObject(s, User.class);
System.out.println(user1);
}
}
public class User {
private Integer id;
private String name;
public User(Integer id, String name) {
this.id = id;
this.name = name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}