java中的拷贝

java中的拷贝

JAVA对象拷贝分为两种方式,一种是引用拷贝(浅拷贝 ),一种是对象拷贝

  1. 引用拷贝: 和对象拷贝的不同之处在于,引用拷贝只会生成一个新的对象引用地址,但两个地址其最终指向的还是同一个对象
  2. 对象拷贝:这种方式会重新生成一个新的对象,生成的新对象与原来的对象没有任何关联
    1. 对象浅拷贝:新对象与原来的对象没有关系,但是如果对象中又引用类型的话,那么这个对象是不会再分配地址的
    2. 对象深拷贝:新对象与其中的引用对象都重新分配地址

引用拷贝图片:
java中的拷贝_第1张图片

引用拷贝代码:

User user1 = new User();
User user2 = user1; // 进行引用拷贝

通过修改user2的值可以引起user1中的变化

对象拷贝中的浅拷贝

需要拷贝的对象实现Cloneable 接口,再调用对象的clone方法可以实现对象的浅拷贝

图片
java中的拷贝_第2张图片

代码

User对象:

public class User implements Cloneable{
    private String name;
    private int age;
    private Teacher teacher;
    
    get,set,构造函数省略
        
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return (User) super.clone();
    }
}

Teachet对象:

public class Teacher {
    private String name;

    public Teacher(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

测试:

public class Main {
    public static void main(String[] args) throws CloneNotSupportedException {
        Teacher teacher = new Teacher("teacher1号");
        User user1 = new User("tang`", 20);
        user1.setTeacher(teacher);
        User clone = (User) user1.clone();
        clone.getTeacher().setName("teacher2号");
        System.out.println(user1.getTeacher().getName());
    }
}

输出的结果为:teacher2号

结论:

  1. clone修改了name之后并没有影响user1的name,这说明clone和user1对象是独立的
  2. clone修改了teacher 对象属性之后user1的teacher对象属性也同时改变了,这说明对象的clone方法并不会把其对象中引用的其他对象进行拷贝,这也是我们俗称的浅拷贝

疑问? 为什么浅拷贝不会拷贝其引用的对象?

  1. 不给其他类强加意义:这个就好比,User类为了能进行浅拷贝就实现了Cloneable 接口,但是其引用对象Teacher没有实现Cloneable 也许说明他本身就不想被拷贝,如果在拷贝User的情况下,同时也把Teacher拷贝了,这不就等于干了一件没有遵循他人同意的事,干了之后人家还不知道,傻傻的以为没人可以通过clone来拷贝出另外一个Teacher
  2. 不破坏其原来对象的代码逻辑:如果User引用的Teacher 是个单例模式的对象,那如果在User拷贝的时候同时也拷贝出了一个Teacher 那是不是就会破坏Teacher这个单例模式对象的逻辑初衷

对象拷贝中的深拷贝

对象需要实现Serializable接口

public class User implements Serializable
public class Teacher implements Serializable

图片:

java中的拷贝_第3张图片

代码:

public class Main {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        Teacher teacher = new Teacher("teacher1号");
        User user1 = new User("我是user1", 20);
        user1.setTeacher(teacher);

        // 序列化写入流中
        ByteOutputStream byteOutputStream = new ByteOutputStream();
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteOutputStream);
        objectOutputStream.writeObject(user1);

        // 反序列化生成user2对象
        ObjectInputStream objectInputStream = new ObjectInputStream(new ByteArrayInputStream(byteOutputStream.getBytes()));
        User user2 = (User) objectInputStream.readObject();
        user2.setName("我是user2");
        user2.getTeacher().setName("teacher2号");

        System.out.println("user1的teacherName: " + user1.getTeacher().getName());
        System.out.println("user1的name: " + user1.getName());
    }
}

输出的结果为:

user1的teacherName: teacher1号

user1的name: 我是user1

进行深拷贝后,改变User2对象中的属性不会对原来User1对象中的属性有任何影响,这说明,User1和User2 不管是属性还是其引用对象都是重新生成互不关联的两个对象

深度拷贝的工具类(适用于所有类型):

public class BeanUtil {
    public static <T> T cloneTo(T src) throws RuntimeException {
        ByteArrayOutputStream memoryBuffer = new ByteArrayOutputStream();
        ObjectOutputStream out = null;
        ObjectInputStream in = null;
        T dist = null;
        try {
            out = new ObjectOutputStream(memoryBuffer);
            out.writeObject(src);
            out.flush();
            in = new ObjectInputStream(new ByteArrayInputStream(memoryBuffer.toByteArray()));
            dist = (T) in.readObject();
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            if (out != null) {
                try {
                    out.close();
                    out = null;
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            if (in != null) {
                try {
                    in.close();
                    in = null;
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
        return dist;
    }
}


你可能感兴趣的:(java基础知识,java)