解析java克隆、拷贝原理 + 案例解析
复习clone 原理用法
浅拷贝:概念
- 数据类型是基本数据类型的浅拷贝,拷贝会直接进行值传递,也就是将原对象的属性赋值一份给新对象,因为是两份不同的数据,所以对其中一个对象的成员变量进行修改,不会影响另一个对象的属性
- 数据类型是引用数据类型的浅拷贝,拷贝进行引用传递,即将地址复制一个给拷贝对象,所以两个对象的引用地址是一样的,如果修改其中一个对象的引用值,会影戏到另一个对象的变量值
例题:
定义英雄类,英雄有角色名字、攻击力、防御力、武器(String)
测试类中实例化一个英雄,拥有一把武器,名字是屠龙、攻击力加成为100
通过内存结构图进行分析,该例题,因为比较简单,就不上传代码
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JSNleIzy-1658759184951)(D:\桌面\浅拷贝.png)]
浅拷贝:概念
深拷贝后的对象与原来的对象是完全隔离的,互不影响,对一个对象的修改并不会影响另一个对象,通过例题更好理解
例题:
定义英雄类,英雄有角色名字、攻击力、防御力、武器
定义武器类,武器有名字、攻击力加成、耐久值
测试类中实例化一个英雄,拥有一把武器,名字是屠龙、攻击力加成为100
耐久值为1000
然后复制这个英雄,复制出来的英雄的武器,名字是屠龙、攻击力加成为100、
耐久值为467
- 思路
- 先创建一个武器类(Arm),因为要进行拷贝,所以要实现 implemensts Cloneable接口
- 一个英雄类(Hero),属性中有武器,Arm arm,因为要进行拷贝,所以要实现implemensts Cloneable接口
- 在英雄类中重定义clone 方法时,要用重新进行 武器的clone,原理很简单,克隆出来了一个英雄,肯定要克隆出来一把相同的武器呀,因为武器是引用数据类型,所以这里一定要写,不要后面的耐久值修改不了
- 最后是测试类,通过英雄类 . 武器类 . 耐久值,进行属性的修改
内存结构图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7fOuQYwq-1658759184952)(D:\图片\实训重点知识\深拷贝原理图.png)]
// 武器类
package kaobeiPractice;
public class Arm implements Cloneable{
private String name;
private double addAttack;
private double endurance;//耐久值
public Arm() {}
public Arm(String name, double addAttack, double endurance) {
this.name = name;
this.addAttack = addAttack;
this.endurance = endurance;
}
public String getName() {
return name;
}
@Override
public String toString() {
return "Arm{" +
"name='" + name + '\'' +
", addAttack=" + addAttack +
", endurance=" + endurance +
'}';
}
@Override
public Arm clone() {
Arm arm =null;
try{
arm = (Arm)super.clone();
}catch (CloneNotSupportedException e ) {
e.printStackTrace();
}
return arm;
}
public void setName(String name) {
this.name = name;
}
public double getAddAttack() {
return addAttack;
}
public void setAddAttack(double addAttack) {
this.addAttack = addAttack;
}
public double getEndurance() {
return endurance;
}
public void setEndurance(double endurance) {
this.endurance = endurance;
}
}
// 英雄类
package kaobeiPractice;
// 使用克隆,要实现cloneable 接口
public class Hero implements Cloneable{
private String name;
private double attack;//攻击力
private double defence;//防御力
private Arm arm;//武器
public Hero() {}
public Hero(String name, double attack, double defence, Arm arm) {
this.name = name;
this.attack = attack;
this.defence = defence;
this.arm = arm;
}
@Override
public String toString() {
return "Hero{" +
"name='" + name + '\'' +
", attack=" + attack +
", defence=" + defence +
", arm=" + arm +
'}';
}
@Override
public Hero clone() {
Hero hero = null;
try {
hero = (Hero)super.clone();
// 英雄都被克隆了一份,武器理所当然的也会被克隆一份赛! 武器也需要克隆一份
setArm(getArm().clone()); //相当于是new 了 一个 Arm 武器
}catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return hero;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getAttack() {
return attack;
}
public void setAttack(double attack) {
this.attack = attack;
}
public double getDefence() {
return defence;
}
public void setDefence(double defence) {
this.defence = defence;
}
public Arm getArm() {
return arm;
}
public void setArm(Arm arm) {
this.arm = arm;
}
}
//测试类
package kaobeiPractice;
public class Test {
public static void main(String[] args) {
Arm arm = new Arm("铁剑?",100,1000);
Hero hero = new Hero("西门飞雪",100,50,arm);
Hero copyHero = hero.clone();
copyHero.setAttack(copyHero.getAttack()+100);
copyHero.getArm().setEndurance(475);
System.out.println(hero);
System.out.println(copyHero);
}
}
感悟
- 进行拷贝的使用要清楚拷贝的步骤,1.拷贝的类一定要实现Cloneable接口
- clone拷贝默认是浅拷贝,拷贝引用数据类型是的时候,要进行深拷贝,一定要考虑在重写clone 方法的时候要clone几个引用数据类型,这里比较容易出问题(我就是出问题出在这里)
- String 虽然是引用数据类型,但是是final 类型,是不能修改的值,同时也有字符串常量池的存在,不需要进行处理
- 今天的克隆学习有点困难,还要继续加油!