JavaSE---Object-clone()

 

一、概述

/**
     *      <what>
     *          创建并返回此对象的一个副本;
     *              (按照原对象,创建一个新的对象[复制原对象的内容])      
     */

  

二、已经存在new或反射等技术,为啥还需要Object的clone方法?

1、new关键字、反射创建对象的弊端
    /**
     *          1、new关键字、反射创建对象的弊端
     *              通过new、反射可以创建内容一样的对象;
     *              但是,创建对象之后,需要通过setter为新对象设置属性值,如果需要创建更多内容一样的对象,setter方法将不断重复;
     *
     *              解决:
     *                  使用Object的clone方法;
     */

public class User{

    private String name;

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                '}';
    }
}

 

private static void newTest() {
        User user = new User();
        user.setName("rose");

        User userCopy = new User();
        userCopy.setName(user.getName());

        System.out.println(user);
        System.out.println(userCopy);

    }

private static void reflectTest() throws ClassNotFoundException, IllegalAccessException, InstantiationException {

        User user = new User();
        user.setName("rose");

        Class<?> userClazz = Class.forName("com.an.object.User");
        User userCopy = (User) userClazz.newInstance();
        userCopy.setName(user.getName());

        System.out.println(user);
        System.out.println(userCopy);
    }

  

2、使用Object的clone方法

    /**
     *  1、需要调用clone方法的对象实现java.lang.Cloneable接口
     *  2、重新clone方法
     */

  

public class User implements Cloneable{

    private String name;

    public String getName() {
        return name;
    }

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

    @Override
    public User clone() throws CloneNotSupportedException {
        return (User) super.clone();
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                '}';
    }
}

  

private static void cloneTest() throws CloneNotSupportedException {

        User user = new User();
        user.setName("rose");

        User userCopy = user.clone();

        System.out.println(user);
        System.out.println(userCopy);

    }

  

三、浅拷贝

/**
     *  <浅拷贝>
     *      what
     *          clone对象 是一个新对象
     *          clone对象的成员变量 与 原对象的成员变量 是同一个数据;
     *
     *      缺点
     *          由于 原对象与clone对象 的成员变量 是同一个数据,任意一个对象对成员变量进行修改,原对象与clone对象的成员变量都会被修改;
     */

  

public class User implements Cloneable{

    private String name;
    private Man man;

    public String getName() {
        return name;
    }

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

    public Man getMan() {
        return man;
    }

    public void setMan(Man man) {
        this.man = man;
    }

    @Override
    public User clone() throws CloneNotSupportedException {
        return (User) super.clone();
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", man=" + man +
                '}';
    }

    public static class Man{
        private String job;

        public String getJob() {
            return job;
        }

        public void setJob(String job) {
            this.job = job;
        }

        @Override
        public String toString() {
            return "Man{" +
                    "job='" + job + '\'' +
                    '}';
        }
    }
}

  

private static void shallowClone() throws CloneNotSupportedException {

        User user = new User();
        user.setName("rose");

        User.Man man = new User.Man();
        man.setJob("teacher");
        user.setMan(man);


        User userCopy = user.clone();

        System.out.println(user.getMan().hashCode()); // 1872034366
        System.out.println(userCopy.getMan().hashCode()); // 1872034366

        user.getMan().setJob("coder");
        System.out.println(user.getMan()); // Man{job='coder'}
        System.out.println(userCopy.getMan()); // Man{job='coder'}

    }

 

四、深拷贝

1、使用java.lang.Cloneable接口深拷贝

/**
     *  <深拷贝>
     *      what
     *          clone对象是一个新对象
     *          clone对象的成员变量 也是一个新对象;
     *
     *      步骤
     *          1、原对象、原对象的成员变量 实现java.lang.Cloneable接口,重写clone方法
     *          2、原对象的clone方法调用成员变量的clone方法;
     *
     *      使用java.lang.Cloneable接口实现深拷贝的弊端:
     *          成员变量重复实现java.lang.Cloneable接口
     *          成员变量重复实现clone方法
     *          原对象的clone方法重复改写
     *
     *      解决
     *          使用IO流的方式进行 深拷贝
     *          (解决重复修改源代码的问题)
     *
     */

  

public class User implements Cloneable{

    private String name;
    private Man man;

    public String getName() {
        return name;
    }

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

    public Man getMan() {
        return man;
    }

    public void setMan(Man man) {
        this.man = man;
    }

    @Override
    public User clone() throws CloneNotSupportedException {
        User clone = (User) super.clone();
        clone.setMan(man.clone());
        return clone;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", man=" + man +
                '}';
    }

    public static class Man implements Cloneable{
        private String job;

        public String getJob() {
            return job;
        }

        public void setJob(String job) {
            this.job = job;
        }

        @Override
        public Man clone() throws CloneNotSupportedException {
            return (Man) super.clone();
        }

        @Override
        public String toString() {
            return "Man{" +
                    "job='" + job + '\'' +
                    '}';
        }
    }
}

  

private static void deepClone() throws CloneNotSupportedException {

        User user = new User();
        user.setName("rose");

        User.Man man = new User.Man();
        man.setJob("teacher");
        user.setMan(man);


        User userCopy = user.clone();

        System.out.println(user.getMan().hashCode()); // 1872034366
        System.out.println(userCopy.getMan().hashCode()); // 1581781576

        user.getMan().setJob("coder");
        System.out.println(user.getMan()); // Man{job='coder'}
        System.out.println(userCopy.getMan()); // Man{job='teacher'}

    }

  

2、使用IO流深拷贝

/**
     *  <深拷贝-使用IO流>
     *      API
     *          ByteArrayOutputStream
     *          ByteArrayInputStream
     *          ObjectOutputStream
     *          ObjectInputStream
     *      步骤
     *          1、创建ByteArrayOutputStream,将数据转换为字节
     *          2、创建ObjectOutputStream,关联ByteArrayOutputStream
     *          3、使用ObjectOutputStream的writeObject,读取要复制的对象
     *          4、使用ByteArrayInputStream读取ByteArrayOutputStream转换的对象字节数据
     *          5、创建ObjectInputStream读取对象字节数据,创建新的对象
     *
     *          原对象及其变量需要实现java.io.Serializable接口
     */

  

package com.an.object;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

/**
 * @author apy
 * @description
 * @date 2022/4/24 17:22
 */
public class User implements Serializable{

    private String name;
    private Man man;

    public String getName() {
        return name;
    }

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

    public Man getMan() {
        return man;
    }

    public void setMan(Man man) {
        this.man = man;
    }

    public User copy(){

        try {
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
            objectOutputStream.writeObject(this);

            ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
            ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);

            User user = (User) objectInputStream.readObject();
            return user;
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", man=" + man +
                '}';
    }

    public static class Man implements Serializable {
        private String job;

        public String getJob() {
            return job;
        }

        public void setJob(String job) {
            this.job = job;
        }

        @Override
        public String toString() {
            return "Man{" +
                    "job='" + job + '\'' +
                    '}';
        }
    }
}

  

private static void ioDeepClone() {

        User user = new User();
        user.setName("rose");

        User.Man man = new User.Man();
        man.setJob("teacher");
        user.setMan(man);


        User userCopy = user.copy();

        System.out.println(user.hashCode()); // 225534817
        System.out.println(userCopy.hashCode()); // 122883338

        System.out.println(user.getMan().hashCode()); // 1878246837
        System.out.println(userCopy.getMan().hashCode()); // 666641942

        user.getMan().setJob("coder");
        System.out.println(user.getMan()); // Man{job='coder'}
        System.out.println(userCopy.getMan()); // Man{job='teacher'}

    }

  

五、为什么使用clone方法需要实现java.lang.Cloneable接口

/**
     *  <为什么使用clone方法需要实现java.lang.Cloneable接口>
     *      下载JDK源码,进入hotspot/src/share/vm/prims/jvm.cpp文件中
     *
     *          // Check if class of obj supports the Cloneable interface.
     *          // All arrays are considered to be cloneable (See JLS 20.1.5)
     *          if (!klass->is_cloneable()) {
     *              ResourceMark rm(THREAD);
     *              THROW_MSG_0(vmSymbols::java_lang_CloneNotSupportedException(), klass->external_name());
     *          }
     *
     *          Check if class of obj supports the Cloneable interface.检查指定的class是否实现java.lang.Cloneable接口(数组默认支持clone);
     *          如果 !klass->is_cloneable() 抛出CloneNotSupportedException;
     *
     *          clone代码:
     *          JVM_ENTRY(jobject, JVM_Clone(JNIEnv* env, jobject handle))
     *          JVMWrapper("JVM_Clone");
     *          Handle obj(THREAD, JNIHandles::resolve_non_null(handle));
     *          const KlassHandle klass (THREAD, obj->klass());
     *          JvmtiVMObjectAllocEventCollector oam;
     */

  

  

 

 

posted on 2022-04-24 17:50  anpeiyong  阅读(26)  评论(0编辑  收藏  举报

导航