• 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 对象,也就是对象描述的指针(指向对象的首地址)

  • 相关阅读:
    华为云云耀云服务器L实例评测|评测使用
    基于Spring Boot的网上租贸系统设计与实现(源码+lw+部署文档+讲解等)
    使用 lua 运行 fscript
    技术分享| anyRTC服务4.3升级
    Web前端开发者的福音,这款APP让你更上一层楼
    智慧医院解决方案
    wx.request请求eggjs报invalid csrf token
    【微信公众号】一、获取 access_token
    【ICRA】ICRA2023 Paper List
    html+javascript 编写的自动根据当前时间问好 早上 中午下午 晚上 还有下班倒计时等等
  • 原文地址:https://blog.csdn.net/qq_41755616/article/details/127815848