JAVA实现深拷贝和浅拷贝
能拷贝的对象肯定要需要实现cloneable接口
浅拷贝
只拷贝值,内存地址还一样,只能拷贝基础类型,引用对象不能拷贝
public class HashText {
public static void main(String[] args) throws CloneNotSupportedException {
Person person = new Person();
person.setName("123");
Friend friend = new Friend();
friend.setName("f1233");
person.setFriend(friend);
System.out.println(person.getName());
System.out.println(person.getFriend().getName());
Person person1 = (Person) person.clone();
person1.setName("456");
// 修改friend的值
person1.getFriend().setName("f456");
System.out.println("基本属性可以拷贝, 不受影响");
System.out.println("person1-"+person1.getName());
System.out.println("person-"+person.getName());
System.out.println("类对象不可以拷贝, 原始对象值也变了");
System.out.println("person1-"+person1.getFriend().getName());
System.out.println("person-"+person.getFriend().getName());
}
static class Person implements Cloneable {
private String name;
private Friend friend;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
public Friend getFriend() {
return friend;
}
public void setFriend(Friend friend) {
this.friend = friend;
}
}
static class Friend {
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
}
输出结果:
123
f1233
基本属性可以拷贝, 不受影响
person1-456
person-123
类对象不可以拷贝, 原始对象值也变了
person1-f456
person-f456
深拷贝
值和内存地址都复制成了新的方法
方法1:clone方式
package com.shinho.plrs.sentinel.service;
import javax.annotation.PostConstruct;
import java.util.HashSet;
public class HashText {
public static void main(String[] args) throws CloneNotSupportedException {
Person person = new Person();
person.setName("123");
Friend friend = new Friend();
friend.setName("f1233");
person.setFriend(friend);
System.out.println(person.getName());
System.out.println(person.getFriend().getName());
Person person1 = (Person) person.clone();
person1.setName("456");
// 修改friend的值
person1.getFriend().setName("f456");
System.out.println("基本属性可以拷贝, 不受影响");
System.out.println("person1-"+person1.getName());
System.out.println("person-"+person.getName());
System.out.println("类对象可以拷贝, 不受影响");
System.out.println("person1-"+person1.getFriend().getName());
System.out.println("person-"+person.getFriend().getName());
}
static class Person implements Cloneable {
private String name;
private Friend friend;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
protected Object clone() throws CloneNotSupportedException {
Person person = (Person) super.clone();
person.friend = (Friend) friend.clone();
return person;
}
public Friend getFriend() {
return friend;
}
public void setFriend(Friend friend) {
this.friend = friend;
}
}
static class Friend implements Cloneable{
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public String toString() {
return "Friend{" +
"name='" + name + '\'' +
'}';
}
}
}
// 输出
123
f1233
基本属性可以拷贝, 不受影响
person1-456
person-123
类对象可以拷贝, 不受影响
person1-f456
person-f1233
方法2:序列化方式
使用场景,针对于包含数组或者复杂对象,不能简单按照方法1方式实现的。
序列化的方式是让每个类都实现Serializable接口,然后通过序列化和反序列化操作达到深克隆的目的
public class HashText {
public static void main(String[] args) throws CloneNotSupportedException, IOException, ClassNotFoundException {
Person person = new Person();
person.setName("123");
Friend friend = new Friend();
friend.setName("f1233");
person.setFriend(friend);
System.out.println(person.getName());
System.out.println(person.getFriend().getName());
// 输出流输出person对象
ByteArrayOutputStream stream = new ByteArrayOutputStream();
ObjectOutputStream outputStream = new ObjectOutputStream(stream);
outputStream.writeObject(person);
// 输入流读入person的数据流
ByteArrayInputStream inputStream = new ByteArrayInputStream(stream.toByteArray());
ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
Person person1 = (Person) objectInputStream.readObject();
// 修改person的值和类对象值
person1.setName("456");
person1.getFriend().setName("f456");
System.out.println("person-原始数据:");
System.out.println(person.getName());
System.out.println(person.getFriend().getName());
System.out.println("person-修改后的数据:");
System.out.println(person1.getName());
System.out.println(person1.getFriend().getName());
}
static class Person implements Serializable {
private String name;
private Friend friend;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
protected Object clone() throws CloneNotSupportedException {
Person person = (Person) super.clone();
person.friend = (Friend) friend.clone();
return person;
}
public Friend getFriend() {
return friend;
}
public void setFriend(Friend friend) {
this.friend = friend;
}
}
static class Friend implements Serializable {
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public String toString() {
return "Friend{" +
"name='" + name + '\'' +
'}';
}
}
}
输出:
123
f1233
person-原始数据:
123
f1233
person-修改后的数据:
456
扩展-Java 创建对象有几种方式
new 关键字
平时使用的最多的创建对象方式
User user=new User();
反射方式
使用 newInstance(),但是得处理两个异常 InstantiationException、IllegalAccessException:
User user=User.class.newInstance();
Object object=(Object)Class.forName("java.lang.Object").newInstance()
clone方法
Object对象中的clone方法来完成这个操作
反序列化操作
调用 ObjectInputStream 类的 readObject() 方法。我们反序列化一个对象,JVM 会给我们创建一个单独的对象。JVM 创建对象并不会调用任何构造函数。一个对象实现了 Serializable 接口,就可以把对象写入到文中,并通过读取文件来创建对象。