• 解析java中的clone方法


    解析java中的clone方法

    1 是什么

    clone方法是Object类中的一个被protected和native修饰的方法,被native就代表它的实现源码是用c++实现的,只不过是我们无法去修改它的代码罢了。

    2 作用

    为子类提供可以重写的clone()方法,目的是实现对象的浅克隆和深克隆

    3 如何用

    3.1 前提

    3.1.1 克隆的原理

    在堆内存中新开辟一段空间,然后把被克隆对象的属性和方法赋值一份到新开辟的空间里面(副本)。

    3.2 浅克隆

    3.2.1 原理

    对于基本数据类型而言,是复制其的副本到新开辟的空间里面

    对于引用数据类型而言,只是复制了引用的地址,并没有开辟新的空间,新的空间里面的引用和被克隆的里面的引用都指向于同一个空间

    3.2.2 浅克隆的实现步骤

    a 实现cloneable接口,这个是判断能否克隆的条件
    b 重写Clone方法,建议采用如下所示的写法
    public 被克隆对象的类型 clone(){
        //不要上抛异常,在方法体里面处理异常以及进行向下转型
       被克隆对象的类型 对象名=null;
       try {
           对象名=(被克隆对象的类型)super.clone();
      } catch (CloneNotSupportedException e) {
                e.printStackTrace();
      }
       return 对象名;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    3.2.3 示例代码

    Hero
    package Work;
    //英雄类,因为需要用克隆,需要实现Cloneable接口
    public class Hero implements Cloneable {
        private String name;
        //名字
        private int attack;
        //攻击力
        private int defence;
        //防御力
        private Weapon weapon;
        //武器
    
        public Hero() {
        }
    
        public Hero(String name, int attack, int defence, Weapon weapon) {
            this.name = name;
            this.attack = attack;
            this.defence = defence;
            this.weapon = weapon;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAttack() {
            return attack;
        }
    
        public void setAttack(int attack) {
            this.attack = attack;
        }
    
        public int getDefence() {
            return defence;
        }
    
        public void setDefence(int defence) {
            this.defence = defence;
        }
    
        public Weapon getWeapon() {
            return weapon;
        }
    
        public void setWeapon(Weapon weapon) {
            this.weapon = weapon;
        }
    
        @Override
        public String toString() {
            return "Hero{" +
                    "name='" + name + '\'' +
                    ", attack=" + attack +
                    ", defence=" + defence +
                    ", weapon=" + weapon +
                    '}';
        }
    
        @Override
        public  Hero clone(){
            Hero hero=null;
            try {
                hero=(Hero)super.clone();
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
            }
            return hero;
        }
    }
    
    
    • 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
    Weapon
    package Work;
    
    public class Weapon implements Cloneable{
        private String name;
        //名字
        private int bonusAttack;
        //攻击力加成
        private int durable;
        //耐久值
    
        public Weapon() {
        }
    
        public Weapon(String name, int bonusAttack, int durable) {
            this.name = name;
            this.bonusAttack = bonusAttack;
            this.durable = durable;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getBonusAttack() {
            return bonusAttack;
        }
    
        public void setBonusAttack(int bonusAttack) {
            this.bonusAttack = bonusAttack;
        }
    
        public int getDurable() {
            return durable;
        }
    
        public void setDurable(int durable) {
            this.durable = durable;
        }
    
        @Override
        public String toString() {
            return "Weapon{" +
                    "name='" + name + '\'' +
                    ", bonusAttack=" + bonusAttack +
                    ", durable=" + durable +
                    '}';
        }
    
        @Override
        public Weapon clone() {
            Weapon weapon=null;
            try {
                weapon=(Weapon)super.clone();
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
            }
            return weapon;
        }
    }
    
    
    • 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
    TestHero
    package Work;
    public class TestHero {
        public static void main(String[] args) {
            Hero hero=new Hero("亚瑟",200,100,new Weapon("屠龙",100,1000));
            Hero copyHero=hero.clone();
            copyHero.getWeapon().setDurable(467);
            copyHero.setName("阿古多");
            System.out.println(hero);
            System.out.println(copyHero);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    3.2.4 示例代码的内存原理图

    a 克隆后

    在这里插入图片描述

    b 更改String属性和引用数据类型属性后

    在这里插入图片描述

    3.2.5 示例代码运行截图

    在这里插入图片描述

    3.3 深克隆

    3.3.1 原理

    对于基本数据类型而言,是复制其的副本到新开辟的空间里面

    对于引用数据类型而言,并不是复制了引用的地址,而是开辟了一个新的引用对象的空间,并把引用地址里面的属性和方法拷贝一份到新的引用对象的空间中,此时克隆对象里面的引用就指向于这个新的空间

    3.3.2 示例代码

    Hero类
    package Work;
    //英雄类,因为需要用克隆,需要实现Cloneable接口
    public class Hero implements Cloneable {
        private String name;
        //名字
        private int attack;
        //攻击力
        private int defence;
        //防御力
        private Weapon weapon;
        //武器
    
        public Hero() {
        }
    
        public Hero(String name, int attack, int defence, Weapon weapon) {
            this.name = name;
            this.attack = attack;
            this.defence = defence;
            this.weapon = weapon;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAttack() {
            return attack;
        }
    
        public void setAttack(int attack) {
            this.attack = attack;
        }
    
        public int getDefence() {
            return defence;
        }
    
        public void setDefence(int defence) {
            this.defence = defence;
        }
    
        public Weapon getWeapon() {
            return weapon;
        }
    
        public void setWeapon(Weapon weapon) {
            this.weapon = weapon;
        }
    
        @Override
        public String toString() {
            return "Hero{" +
                    "name='" + name + '\'' +
                    ", attack=" + attack +
                    ", defence=" + defence +
                    ", weapon=" + weapon +
                    '}';
        }
    
        @Override
        public  Hero clone(){
            Hero hero=null;
            try {
                hero=(Hero)super.clone();
                //给weapon属性也给克隆一下
                setWeapon(getWeapon().clone());
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
            }
            return hero;
        }
    }
    
    
    • 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
    Weapon类
    package Work;
    
    public class Weapon implements Cloneable{
        private String name;
        //名字
        private int bonusAttack;
        //攻击力加成
        private int durable;
        //耐久值
    
        public Weapon() {
        }
    
        public Weapon(String name, int bonusAttack, int durable) {
            this.name = name;
            this.bonusAttack = bonusAttack;
            this.durable = durable;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getBonusAttack() {
            return bonusAttack;
        }
    
        public void setBonusAttack(int bonusAttack) {
            this.bonusAttack = bonusAttack;
        }
    
        public int getDurable() {
            return durable;
        }
    
        public void setDurable(int durable) {
            this.durable = durable;
        }
    
        @Override
        public String toString() {
            return "Weapon{" +
                    "name='" + name + '\'' +
                    ", bonusAttack=" + bonusAttack +
                    ", durable=" + durable +
                    '}';
        }
    
        @Override
        public Weapon clone() {
            Weapon weapon=null;
            try {
                weapon=(Weapon)super.clone();
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
            }
            return weapon;
        }
    }
    
    
    • 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
    TestHero类
    package Work;
    public class TestHero {
        public static void main(String[] args) {
            Hero hero=new Hero("亚瑟",200,100,new Weapon("屠龙",100,1000));
            Hero copyHero=hero.clone();
            copyHero.getWeapon().setDurable(467);
            copyHero.setAttack(500);
            copyHero.setName("阿古多");
            System.out.println(hero);
            System.out.println(copyHero);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    3.3.3 示例代码的内存原理图

    a 克隆后

    在这里插入图片描述

    b 修改克隆对象的属性和方法

    在这里插入图片描述

    3.3.4 示例代码运行截图

    在这里插入图片描述

  • 相关阅读:
    ThreadLocal
    Apache HBase MTTR 优化实践
    【零基础学QT】第十章 项目打包,利用Inno Setup制作软件安装包
    Linux基本指令(一)
    9.20 QT作业
    iOS开发Swift-5-自动布局AutoLayout-摇骰子App
    STM32驱动MPU6050基于IIC协议
    Nginx笔记-vue项目刷新出现404(try_files和index)
    Vue开发实战02-vue项目添加状态管理Vuex,路由router,以及http请求axios
    优雅而高效的JavaScript——防抖和节流
  • 原文地址:https://blog.csdn.net/SSS4362/article/details/125977265