java基础内容笔记--对象的克隆

【注意,本人小白一个,以下是个人根据教程的理解,如有疑惑,出错的地方,希望大家能够留言指出来,相互学习进步。】

        教程中出现克隆的内容,一开始看的时候是有点蒙的,什么克隆,是和生物技术一样的吗?克隆有什么用,根据脑子里面的问题,往下看了这个内容,用一个例子来介绍一下java的克隆。

演示例子

class Human1{
	String name; //人类名称
	String sex;  //性别
	int age; //年龄
	String addr; //地址
	//定义构造函数
	Human1(String name,String sex,int age,String addr) {
		//复习一下,this关键字在这里是获得默认构造函数
		this.name = name;
		this.sex = sex;
		this.age = age;
		this.addr = addr;
	}
	void work(){
		System.out.println("我在工作");//工作方法
	}
	void eat(){
		System.out.println("我在吃饭");//吃饭方法
	}
}
public class CloneDemo1 {
	public static void main(String[] args) {
		Human1 zhangsan = new Human1("张三","男", 23, "北京");
		System.out.println("张三的名字:"+zhangsan.name);
		Human1 lisi = zhangsan;
		lisi.name = "李四";
		System.out.println("把李四的名字改为李四");
		System.out.println("李四的名字:"+lisi.name);
		System.out.println("张三的名字:"+zhangsan.name);
	}
}
运行结果:
第二个构造函数被调用
第三个构造函数被调用
张三的名字:张三
把李四的名字改为李四
李四的名字:李四
张三的名字:李四
解读一下例子的逻辑:
        例子中创建了一个Human的一个类,并且新建了一个构造函数接收用户打呼噜的信息,还有两个方法,在main方法中,创建了human的对象zhangsan,还把zhangsan赋值给lisi,这时候,zhangsan和lisi都是同样的属性,我们通过lisi.name来修改名字,但是在输出zhangsan和lisi的属性时候,发现即使修改了lisi的属性,它们两个的属性在输出后还是一样(运行结果),修改的结果就没有作用了,原因是对象的指引问题,创建zhangsan对象的时候,我们的zhangsan是指向一个Human的对象,而zhangshan只是一个地址去指向它的,lisi得到zhansan的地址,也是指向Human的一个对象,所以,zhangsan和lisi都是指向同一个Human对象的地址,所以单纯的通过lisi.name去修改的话,zhangsan也会受到影响。这时候,克隆的存在就是有意义的了,在Object中提供了一个方法clone,它的定义如下:
protected Object clone() throws CloneNotSupportedException
创建并返回此对象的一个副本,它在类中可以使用下面的语句
super.clone()
        调用这个方法的时候,得到的是一个Object的对象,需要对它进行类型转换才能得到相应的对象,调用这个方法需要注意的是,类中使用clone方法的时候,这个类需要实现Cloneable接口,并且把clone方法定义为public。
【Human.java】
class Human implements Cloneable {
	String name;//人类名称
	String sex;//性别
	int age;//年龄
	String addr;//地址
	Human(String name,String sex,int age,String addr){
		this.name = name;
		this.sex = sex;
		this.age = age;
		this.addr = addr;
	}
	void work(){
		System.out.println("我在工作");
	}
	void eat(){
		System.out.println("我在吃饭");
	}
	public Object clone(){
		Human h = null;
		try {
			h = (Human)super.clone();
		} catch (CloneNotSupportedException e) {
			e.printStackTrace();
		}
		return h;		
	}
}
这里使用了一个代码块,try...catch,这个是异常的语句,今后涉及详细的内容就在说明。
【CloneDemo.java】
public class CloneDemo {

	public static void main(String[] args) {
	Human zhangsan = new Human("张三","男",23,"北京");//创建人类对象
	Human lisi = (Human)zhangsan.clone();//zhangsan.getClone();
	lisi.name = "李四";//赋值
	System.out.println("把李四的名字改为李四");
	System.out.println("李四的名字:"+lisi.name);
	System.out.println("张三的名字:"+zhangsan.name);
	}

}
运行结果:

李四的名字:李四
张三的名字:张三
这样,lisi修改名字后就不会影响到zhangsan的内容了。但是这样的克隆还是有个问题,在多对象的情况下,修改属性,还是会修改到原本对象的属性,导致其他对象的属性一起发生改变。

演示例子:

class Addr {
	String country; // 国家
	String province; // 地区
	String city; // 城市

	Addr(String country, String province, String city) {
		this.country = country;
		this.province = province;
		this.city = city;
	}
}

class Human1 implements Cloneable {
	String name; // 名称
	int age; // 年龄
	Addr addr; // 地址

	Human1(String name, int age, Addr addr) {
		this.name = name;
		this.age = age;
		this.addr = addr;
	}

	public Object clone() { // 克隆方法
		Human1 h = null;
		try {
			h = (Human1) super.clone();
		} catch (CloneNotSupportedException e) {
			e.printStackTrace();
		}
		return h;
	}
}

public class TestClone {
	public static void main(String[] args) {
		Addr addr = new Addr("中国", "北京", "朝阳区"); // 创建一个地址对象
		Human1 zhangsan = new Human1("zhagnsan", 24, addr); // 创建一个张三的人类对象
		Human1 lisi = (Human1) zhangsan.clone(); // 克隆出一个李四来
		System.out.println("张三的地址"); // 显示张三的地址
		System.out.println(zhangsan.addr.country + zhangsan.addr.province
				+ zhangsan.addr.city);
		System.out.println("李四的地址"); // 显示李四的地址
		System.out.println(lisi.addr.country + lisi.addr.province
				+ lisi.addr.city);
		lisi.addr.country = "中国"; // 改变李四的地址
		lisi.addr.province = "山东";
		lisi.addr.city = "青岛";
		System.out.println("修改李四的地址为:中国山东青岛");
		System.out.println("张三的地址"); // 显示张三的地址
		System.out.println(zhangsan.addr.country + zhangsan.addr.province
				+ zhangsan.addr.city);
		System.out.println("李四的地址"); // 显示李四的地址
		System.out.println(lisi.addr.country + lisi.addr.province
				+ lisi.addr.city);
	}
}
运行结果:
张三的地址
中国北京朝阳区
李四的地址
中国北京朝阳区
修改李四的地址为:中国山东青岛
张三的地址
中国山东青岛
李四的地址
中国山东青岛
        这个就涉及到浅克隆的问题了,教程介绍的原文:clone 是 Object 类提供的方法,Object 并不知道具体类的实现细节,它只是按照字段进行一个个拷贝。对于可变对象变量,它获得只是对象的地址,拷贝得到的对象中如果有变量指向可变对象,原对象和克隆得到的对象仍然所含的可变对象仍指向同一个对象,所以改变其中一个对象仍会改变另一个。注意虽然 String 是作为对象出现的,但是由于 String 的不可变性,所以在克隆中 String 不会产生这样的问题。简单的来说,类A中使用了一个克隆方法,另一个类B没有使用,生成一个有克隆类A的对象a,通过对象去获得没有克隆类B的属性,再赋值给另一个有克隆类C的对象c,c对象通过类B修改里面的属性,a对象也会受到影响。
修改原有的程序如下,实现出c对象修改类B的属性后不会影响到对象a的属性。
public class TestClone {
	public static void main(String[] args) {
		Addr addr = new Addr("中国", "北京", "朝阳区"); // 创建一个地址对象
		Human1 zhangsan = new Human1("zhagnsan", 24, addr); // 创建一个张三的人类对象
		Human1 lisi = (Human1) zhangsan.clone(); // 克隆出一个李四来
		System.out.println("张三的地址"); // 显示张三的地址
		System.out.println(zhangsan.addr.country + zhangsan.addr.province
				+ zhangsan.addr.city);
		System.out.println("李四的地址"); // 显示李四的地址
		System.out.println(lisi.addr.country + lisi.addr.province
				+ lisi.addr.city);
		Addr addr1 = new Addr("中国", "山东", "青岛");
		lisi.addr = addr1;
		System.out.println("修改李四的地址为:中国山东青岛");
		System.out.println("张三的地址");
		System.out.println(zhangsan.addr.country + zhangsan.addr.province
				+ zhangsan.addr.city);
		System.out.println("李四的地址");
		System.out.println(lisi.addr.country + lisi.addr.province
				+ lisi.addr.city);
	}
}

运行结果:
张三的地址
中国北京朝阳区
李四的地址
中国北京朝阳区
修改李四的地址为:中国山东青岛
张三的地址
中国北京朝阳区
李四的地址
中国山东青岛

这种方法不是最优的方法,不应该在后面才去修改实现的方法,而是应该在实现方法前的类中就调用克隆这样就能实现修改对象类的属性后不会影响到其他的对象。

演示代码:

class Addr implements Cloneable {
	String country; // 表示地址的国家
	String province; // 表示地址的地区
	String city; // 表示地址的城市

	Addr(String country, String province, String city) {
		this.country = country;
		this.province = province;
		this.city = city;
	}

	public Object clone() { // 克隆方法
		Addr addr = null;
		try {
			addr = (Addr) super.clone();
		} catch (CloneNotSupportedException e) {
			e.printStackTrace();
		}
		return addr;
	}
}

class Human1 implements Cloneable {
	String name; // 名称
	int age; // 年龄
	Addr addr; // 地址

	Human1(String name, int age, Addr addr) {
		this.name = name;
		this.age = age;
		this.addr = addr;
	}

	public Object clone() {
		Human1 h = null;
		try {
			h = (Human1) super.clone();
			h.addr = (Addr) this.addr.clone();
		} catch (CloneNotSupportedException e) {
			e.printStackTrace();
		}
		return h;
	}
}

public class TestClone {
	public static void main(String[] args) {
		Addr addr = new Addr("中国", "北京", "朝阳区"); // 创建一个地址对象
		Human1 zhangsan = new Human1("zhagnsan", 24, addr); // 创建一个张三的人类对象
		Human1 lisi = (Human1) zhangsan.clone(); // 克隆出一个李四来
		System.out.println("张三的地址"); // 显示张三的地址
		System.out.println(zhangsan.addr.country + zhangsan.addr.province
				+ zhangsan.addr.city);
		System.out.println("李四的地址"); // 显示李四的地址
		System.out.println(lisi.addr.country + lisi.addr.province
				+ lisi.addr.city);
		lisi.addr.country = "中国"; // 改变李四的地址
		lisi.addr.province = "山东";
		lisi.addr.city = "青岛";
		System.out.println("修改李四的地址为:中国山东青岛");
		System.out.println("张三的地址");
		System.out.println(zhangsan.addr.country + zhangsan.addr.province
				+ zhangsan.addr.city);
		System.out.println("李四的地址");
		System.out.println(lisi.addr.country + lisi.addr.province
				+ lisi.addr.city);
	}
}

运行结果:

张三的地址
中国北京朝阳区
李四的地址
中国北京朝阳区
修改李四的地址为:中国山东青岛
张三的地址
中国北京朝阳区
李四的地址
中国山东青岛
小结,在看到网上的一些街道对象的克隆中,看到有深度克隆,应该是区别出浅克隆的方式,在对象使用类的数量多的时候,应该用的是深度克隆。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值