JavaSE_Clone

1、什么是深克隆与浅克隆?

  1. 浅克隆:在浅克隆中,如果原型对象的成员变量是值类型,将复制一份给克隆对象;如果原型对象的成员变量是引用类型,则将引用对象的地址复制一份给克隆对象,也就是说原型对象和克隆对象的成员变量指向相同的内存地址。
    简单来说,在浅克隆中,当对象被复制时只复制它本身和其中包含的值类型的成员变量,而引用类型的成员对象并没有复制。
  2. 深克隆:在深克隆中,无论原型对象的成员变量是值类型还是引用类型,都将复制一份给克隆对象,深克隆将原型对象的所有引用对象也复制一份给克隆对象。
    简单来说,在深克隆中,除了对象本身被复制外,对象所包含的所有成员变量也将复制。

2、怎样实现对象的浅克隆?

将“某电商平台类”进行浅克隆。

/*
 * 	买家类(某电商平台)
 */
public class Buyer {
	
	private String buyerNick; //买家昵称
	private char sex;	//买家性别
	private int integral; //买家积分
	
	//	构造方法
	public Buyer(String buyerNick, char sex, int integral) {
		this.buyerNick = buyerNick;
		this.sex = sex;
		this.integral = integral;
	}
	@Override
	public String toString() {
		return "买家信息 [买家昵称=" + buyerNick + ", 买家性别=" + sex + ", 买家积分=" + integral + "]";
	}
	public String getBuyerNick() {
		return buyerNick;
	}
	public void setBuyerNick(String buyerNick) {
		this.buyerNick = buyerNick;
	}
	public char getSex() {
		return sex;
	}
	public void setSex(char sex) {
		this.sex = sex;
	}
	public int getIntegral() {
		return integral;
	}
	public void setIntegral(int integral) {
		this.integral = integral;
	}	
}
  1. 实现Cloneable接口:
public interface Cloneable {
}

通过Cloneable接口的源码可知:该接口为一个空接口,所以该接口是一个标示,标示该类可以被克隆,如果没有实现Cloneable接口当调用克隆方法时候会抛出CloneNotSupportedException异常!
2. 覆盖Object中的clone方法:

protected native Object clone() throws CloneNotSupportedException;

通过Object类中的clone方法的源码可知:该方法是受保护的所以只能由子类重写后调用。
重写后:

	//对象的浅克隆
	@Override
	public Buyer clone() throws CloneNotSupportedException {
		return (Buyer)super.clone();
	}
  1. 对浅克隆进行测试
/**
 * 对象的浅克隆
 * 
 */
public class Test {
	public static void main(String[] args) throws CloneNotSupportedException {
		//	创建买家对象1
		Buyer buyer01 = new Buyer("张无忌", '男', 12800);
		//	创建买家对象2(与买家1数据一样)
		//	复制对象buyer01产生新的对象。
		Buyer buyer02 = buyer01.clone();
		//	修改买家2的买家昵称。
		//	修改买家2昵称不会造成买家1昵称的改变。
		buyer02.setBuyerNick("东方不败");
		
		System.out.println(buyer01);
		System.out.println(buyer02);
	}
}

运行结果:

买家信息 [买家昵称=张无忌, 买家性别=, 买家积分=12800]
买家信息 [买家昵称=东方不败, 买家性别=, 买家积分=12800]

提出问题:当Buyer类中添加一个引用属性Adress(送货地址类)

/*
 * 	送货地址类
 */
public class Address{
	private String contact; //联系人
	private String addressContent; //具体地址
	private String phoneNumber; //联系手机号码
	

	public Address(String contact, String addressContent, String phoneNumber) {
		super();
		this.contact = contact;
		this.addressContent = addressContent;
		this.phoneNumber = phoneNumber;
	}
	@Override
	public String toString() {
		return "地址信息 [contact=" + contact + ", addressContent=" + addressContent + ", phoneNumber=" + phoneNumber
				+ "]";
	}
	public String getContact() {
		return contact;
	}
	public void setContact(String contact) {
		this.contact = contact;
	}
	public String getAddressContent() {
		return addressContent;
	}
	public void setAddressContent(String addressContent) {
		this.addressContent = addressContent;
	}
	public String getPhoneNumber() {
		return phoneNumber;
	}
	public void setPhoneNumber(String phoneNumber) {
		this.phoneNumber = phoneNumber;
	}
}
package com.apesource.demo01;

/*
 * 	买家类(某电商平台)
 */
public class Buyer{
	
	private String buyerNick; //买家昵称
	private char sex;	//买家性别
	private int integral; //买家积分
	private Address address;//送货地址
	
	//	构造方法
	public Buyer(String buyerNick, char sex, int integral) {
		this.buyerNick = buyerNick;
		this.sex = sex;
		this.integral = integral;
	}
	@Override
	public String toString() {
		return "买家信息 [买家昵称=" + buyerNick + ", 买家性别=" + sex + ", 买家积分=" + integral + ",送货地址=" + address + "]";
	}
	
	public Address getAddress() {
		return address;
	}
	public void setAddress(Address address) {
		this.address = address;
	}
	public String getBuyerNick() {
		return buyerNick;
	}
	public void setBuyerNick(String buyerNick) {
		this.buyerNick = buyerNick;
	}
	public char getSex() {
		return sex;
	}
	public void setSex(char sex) {
		this.sex = sex;
	}
	public int getIntegral() {
		return integral;
	}
	public void setIntegral(int integral) {
		this.integral = integral;
	}
	
}

如果按照浅克隆的方式对Buyer类的对象进行克隆,那么不会实现对属性address的克隆:所以要进行深克隆。

3、怎样实现对象的深克隆?

通过覆盖Object类中的clone方法进行深克隆!

  1. 实现Cloneable接口:
  2. 覆盖Object中的clone方法:(当然)
    Address类中实现Cloneable接口覆盖clone方法。
	@Override
	protected Address clone() throws CloneNotSupportedException {
		return (Address)super.clone();
	}

Buyer类中实现Cloneable接口覆盖clone方法。

	//深克隆
	@Override
	protected Buyer clone() throws CloneNotSupportedException {
		//克隆新的买家对象
		Buyer cloneBuyer = (Buyer)super.clone();
		//克隆买家对象中的收货地址对象。
		Address cloneAddress = cloneBuyer.getAddress().clone();
		cloneBuyer.setAddress(cloneAddress);
		return cloneBuyer;
	}

注意:Buyer中的clone方法需要手动调用Address的clone方法对属性进行克隆。
测试:

/*
 * 	深复制
 */
public class Test03 {
	public static void main(String[] args) throws CloneNotSupportedException {
		//	创建买家对象1
		Buyer  buyer01 = new Buyer("西门吹牛",'男', 250); 
		
		//	为买家对象1设置默认的送货地址
		Address address = new Address("西门吹牛","西安市钟楼","13966554431");
		buyer01.setDefaultAddres(address);
		
		//	复制买家对象1(克隆)
		Buyer buyer02 = buyer01.clone();
		
		//	改变买家2的收货地址中的联系人
		buyer02.getDefaultAddres().setContact("孙悟空");
		
		System.out.println("买家1:" + buyer01);
		System.out.println("买家2:" + buyer02);
		System.out.println("----------------------------------");
		System.out.println("买家对象1:" + buyer01.hashCode());
		System.out.println("买家对象2:" + buyer02.hashCode());
		System.out.println("----------------------------------");
		System.out.println("买家对象1的默认收货地址对象:" + buyer01.getDefaultAddres().hashCode());
		System.out.println("买家对象2的默认收货地址对象:" + buyer02.getDefaultAddres().hashCode());
	}
}

运行结果:

买家1:买家信息 [买家昵称=西门吹牛, 买家性别=, 买家积分=250,送货地址=地址信息 [contact=西门吹牛, addressContent=西安市钟楼, phoneNumber=13966554431]]
买家2:买家信息 [买家昵称=西门吹牛, 买家性别=, 买家积分=250,送货地址=地址信息 [contact=孙悟空, addressContent=西安市钟楼, phoneNumber=13966554431]]
----------------------------------
买家对象1:366712642
买家对象2:1829164700
----------------------------------
买家对象1的默认收货地址对象:2018699554
买家对象2的默认收货地址对象:1311053135

通过对象的序列化的方法进行深克隆!

源码:

import java.io.Serializable;

/*
 * 	武器类
 * 	使用序列化和反序列化,实现"深拷贝"
 */
public class Weapon implements Serializable {
	
	/**
	 * 
	 */
	private static final long serialVersionUID = -198218457098370816L;
	
	private String name; //武器名称
	private int number;	//武器子弹数量
	
	public Weapon(String name, int number) {
		super();
		this.name = name;
		this.number = number;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getNumber() {
		return number;
	}
	public void setNumber(int number) {
		this.number = number;
	}
}

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

import com.apesource.demo02.Weapon;

/*
 * 	机器人类
 * 	使用序列化和反序列化,实现"深拷贝"
 */
public class Robot implements Serializable{
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 408666801749150102L;
	
	private String level; //机器人等级
	private int value; //机器人的生命值
	private Weapon weapon; //机器人的武器

	public Robot(String level, int value) {
		super();
		this.level = level;
		this.value = value;
	}
	
	//	自定义的"深拷贝"方法
	public Robot deepClone() throws Exception{
		//	将“当前Robot对象”转换为字节流(序列化)
		ByteArrayOutputStream bos = new ByteArrayOutputStream(); //字节数组输出流
		ObjectOutputStream oos = new ObjectOutputStream(bos); //对象输出流(用于实现序列化)
		oos.writeObject(this); //将当前Robot对象对象,写入字节数组输出流bos
		
		//	将字节流转换为“新的Robot对象”(反序列化)
		ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); // 创建字节数组输入流,传入"序列化后的字节流"
		ObjectInputStream ois = new ObjectInputStream(bis); //对象输入流(用于实现反序列化)
		Robot newRobot = (Robot)ois.readObject(); //将字节流转换为一个新的Robot对象
		return newRobot;
	}
	public String getLevel() {
		return level;
	}
	public void setLevel(String level) {
		this.level = level;
	}
	public int getValue() {
		return value;
	}
	public void setValue(int value) {
		this.value = value;
	}
	public Weapon getWeapon() {
		return weapon;
	}
	public void setWeapon(Weapon weapon) {
		this.weapon = weapon;
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值