• CloneNotSupportedException的解决方案 + Object的clone方法分析


    CloneNotSupportedException的解决方案

    引入问题:

    在一次测试clone方法时,D类Override了Object类的clone方法

    public class D {
    
        private Integer A1;
        private Integer A2;
    
        public D() {
        }
    
        public D(Integer a1, Integer a2 {
            A1 = a1;
            A2 = a2;
        }
    
        @Override
        protected Object clone() throws CloneNotSupportedException {
            return super.clone();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    在测试类中执行clone方法报错了

    public class Test5 {
    
        public static void main(String[] args) {
    
            D p  = new D();
            D p2 = null;
            try {
                p2 = (D)p.clone();
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
            }
            System.out.println(p == p2);
    
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    在这里插入图片描述

    抛出了 CloneNotSupportedException

    寻找原因:

    既然是重写自Object的clone方法,那么去看看Object对该方法的定义:

    protected native Object clone() throws CloneNotSupportedException;
    
    • 1

    其中对于异常抛出的描述如下:

    Throws:
    CloneNotSupportedException – if the object’s class does not support the Cloneable interface. Subclasses that override the clone method can also throw this exception to indicate that an instance cannot be cloned.

    如果对象的class不实现Cloneable接口,子类重写clone方法会同样抛出异常表示实例不能被克隆;

    哦?

    那不意思就是说:你要不父类实现Cloneable接口,要不就子类实现Cloneable

    两个测试代码:

    测试1: 在父类上实现Cloneable接口

    public class TestClone {
    
        public static void main(String[] args) throws CloneNotSupportedException {
            Father father = new Father();
            Father fatherClone = (Father) father.clone();
    
            Son son = new Son();
            Son sonClone = (Son) son.clone();
    
            System.out.println(father==fatherClone);
            System.out.println(son==sonClone);
    
        }
    
    }
    
    class Father implements Cloneable{
        private Integer f1;
        private Integer f2;
    
        public Father() {
        }
    
        public Father(Integer f1, Integer f2) {
            this.f1 = f1;
            this.f2 = f2;
        }
    
        @Override
        protected Object clone() throws CloneNotSupportedException {
            return super.clone();
        }
    }
    
    
    class Son extends Father{
        private Integer s1;
        private Integer s2;
    
        public Son() {
        }
    
        public Son(Integer s1, Integer s2) {
            this.s1 = s1;
            this.s2 = s2;
        }
    
        @Override
        protected Object clone() throws CloneNotSupportedException {
            return super.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

    不出意外,没有任何问题

    在这里插入图片描述

    测试2:在子类上实现Cloneable接口

    public class TestClone {
    
        public static void main(String[] args) throws CloneNotSupportedException {
    //        Father father = new Father();
    //        Father fatherClone = (Father) father.clone();
    
            Son son = new Son();
            Son sonClone = (Son) son.clone();
    
    //        System.out.println(father==fatherClone);
            System.out.println(son==sonClone);
    
        }
    
    }
    
    class Father {
        private Integer f1;
        private Integer f2;
    
        public Father() {
        }
    
        public Father(Integer f1, Integer f2) {
            this.f1 = f1;
            this.f2 = f2;
        }
    
        @Override
        protected Object clone() throws CloneNotSupportedException {
            return super.clone();
        }
    }
    
    
    class Son extends Father implements Cloneable{
        private Integer s1;
        private Integer s2;
    
        public Son() {
        }
    
        public Son(Integer s1, Integer s2) {
            this.s1 = s1;
            this.s2 = s2;
        }
    
        @Override
        protected Object clone() throws CloneNotSupportedException {
            return super.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

    执行父类的clone报错,但是执行子类的clone没得问题

    在这里插入图片描述

    SO:

    哪个类的需要clone,就在那个类在重写clone方法,并且在那个类或者其父类中实现Cloneable接口

    详细分析clone方法的实现:

    由于Object的clone方法是native修饰的,也就是虚拟机内部实现的方法

    根据Hotspot虚拟机定义,找到Object.c

    在这里插入图片描述

    为什么要实现Cloneable接口?

    在JVM_Clone方法中有这样一段判断:

    在这里插入图片描述

    很明显,虚拟机给你抛出的异常

    为什么会出现地址不同的情况?

    在这里插入图片描述

    很明显,直接在堆内存中执行allocate方法开辟新的对象空间

    并返回一个 oop 对象,也就是对象描述的指针(指向对象的首地址)

  • 相关阅读:
    English语法_介词 - at
    linux 虚拟机下安装docker
    关于计算机丢失MSVCP140.dll是什么意思?MSVCP140.dll缺失的5个解决方案分享
    爱上开源之golang入门至实战-第二章语言基础
    基于卷积神经网络实现手写数字识别
    内存卡剪切后怎么恢复
    quickapp_快应用
    编译原理:语法分析(自顶向下)
    动态链接库(六)--解决不同编译环境导致的名字改编问题
    视频太大怎么压缩变小?把视频变小这样做
  • 原文地址:https://blog.csdn.net/qq_41755616/article/details/127815848