JavaSE---Object-clone()

 

一、概述

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

  

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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 + '\'' +
                '}';
    }
}

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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
2
3
4
/**
 *  1、需要调用clone方法的对象实现java.lang.Cloneable接口
 *  2、重新clone方法
 */

  

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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 + '\'' +
                '}';
    }
}

  

1
2
3
4
5
6
7
8
9
10
11
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);
 
    }

  

三、浅拷贝

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

  

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
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 + '\'' +
                    '}';
        }
    }
}

  

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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接口深拷贝

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
     *  <深拷贝>
     *      what
     *          clone对象是一个新对象
     *          clone对象的成员变量 也是一个新对象;
     *
     *      步骤
     *          1、原对象、原对象的成员变量 实现java.lang.Cloneable接口,重写clone方法
     *          2、原对象的clone方法调用成员变量的clone方法;
     *
     *      使用java.lang.Cloneable接口实现深拷贝的弊端:
     *          成员变量重复实现java.lang.Cloneable接口
     *          成员变量重复实现clone方法
     *          原对象的clone方法重复改写
     *
     *      解决
     *          使用IO流的方式进行 深拷贝
     *          (解决重复修改源代码的问题)
     *
     */

  

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
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 + '\'' +
                    '}';
        }
    }
}

  

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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流深拷贝

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

  

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
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 + '\'' +
                    '}';
        }
    }
}

  

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
     *  <为什么使用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   anpeiyong  阅读(27)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· .NET10 - 预览版1新功能体验(一)
历史上的今天:
2019-04-24 SpringCloud---API网关服务---Spring Cloud Zuul

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
点击右上角即可分享
微信分享提示