java中的clone()方法的研究---(6)如何编写正确的clone()方法:StringBuffer,StringBuilder

在自定义类Person中添加一个新的StringBuffer, StringBuilder属性


四:StringBuffer, StringBuilder:是对象的类型


在自定义类Person中添加新的属性:StringBuffer, StringBuilder


package tt.vo;

public class Person implements Cloneable {

	// 基本数据类型
	private int age;

	// Wrapper Class类型
	private Integer height;

	// String 类型
	private String name;
	
	// StringBuffer
	private StringBuffer address1;
	
	// StringBuilder
	private StringBuilder address2;

	@Override
        // 默认的clone()实现方式
	public Person clone() throws CloneNotSupportedException {
		Person p = (Person) super.clone();
		return p;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}


	public Integer getHeight() {
		return height;
	}

	public void setHeight(Integer height) {
		this.height = height;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public StringBuffer getAddress1() {
		return address1;
	}

	public void setAddress1(StringBuffer address1) {
		this.address1 = address1;
	}

	public StringBuilder getAddress2() {
		return address2;
	}

	public void setAddress2(StringBuilder address2) {
		this.address2 = address2;
	}

	@Override
	public String toString() {
		return "Person [age=" + age + ", height=" + height + ", name=" + name
				+ ", address1=" + address1 + ", address2=" + address2 + "]";
	}

	
}


注意,这里一直所讲的是默认的clone()行为,对各种类型属性的影响。

默认的clone()方法,就是对属性不用做额外的处理:

	@Override
	public Person clone() throws CloneNotSupportedException {
		Person p = (Person) super.clone();
		return p;
	}



---------------------------------------------------------------下面开始测试了------------------------------------------------------------------

测试类TestMain:


package tt;

import tt.vo.Person;

public class TestMain {

	public static void main(String[] args) throws CloneNotSupportedException {
		// initialize Person p
		Person p = new Person();
		
		// int 
		p.setAge(18);
		
		// Integer
		p.setHeight(162);
		
		// String
		p.setName("郭美美");
		
		// StringBuffer
		p.setAddress1(new StringBuffer("中国北京"));
		
		// StringBuilder
		p.setAddress2(new StringBuilder("美国纽约"));
		
		System.out.println("p:" + p);

		Person pclone = p.clone();
		System.out.println("pclone:" + pclone);
		
		
		System.out.println("-------------after set-------------------");
		
		p.setAge(180);	
		p.setHeight(190);
		p.setName("郭美美不美");
		pclone.getAddress1().append("!!!");
		pclone.getAddress2().append("......");
		
		System.out.println("p:" + p);
		System.out.println("pclone:" + pclone);
	}

	
	
}

当clone()结束时候,加断点,我们来看看StringBuffer, StringBuilder的克隆情况


debug截图:


(ps: 每次debug时候,id所分配的号码会不一样)


通过debug可以发现:

  • 只要是对象的类型都会有id
  • 只要是对象的类型,通过默认的clone()方法克隆出来的结果,都是浅克隆
  • p.address1和pclone.address1 指向的是同一个对象id(24)
  • p.address2和pclone.address2 指向的是同一个对象id(28)


此时进一步测试,便会发现StringBuffer, StringBuilder与String类型的本质区别:
debug截图:

通过debug可以发现:

  • 修改了pclone.address1 和 pclone.address2就等同于修改了p.address1和p.address2。因为他们指向的都是同一个id(24 28)
  • 并且StringBuffer 和 StringBuilder 类内部维护的value(可以看其源代码 是 char[] value),也是同一个id(51 54)
  • 这里同时,是使用append()方法,自然的pclone.address1在append之后,p.address1的内容也跟着变了。反之亦然。
  • 但是对于String类型的p.name来说,在进行p.setName("郭美美不美");(等同于p.name = "郭美美不美") 之后,
    JVM会开辟一块新的内存空间,用来存储"郭美美不美"字符串,并且将p.name,指向这个新的地址引用。
    这就是为什么String类型在频繁的赋值操作之后,会耗费内存的原因。
    因此,推荐使用StringBuffer 和 StringBuilder 的方法,操作字符串,用来节省内存空间。

----------------来看看String和StringBuffer源代码的区别:---------------------------------------



  • AbstractStringBuilder是StringBuffer和StringBuilder的父类
  • AbstractStringBuilder其内部维护的是char[] value; 注意没有final修饰
  • String其内部维护的是private final char value[]; 注意有final修饰
  • 我个人感觉,这个是否有final修饰是本质区别。还望大师们指教!!!奋斗

--------------------------------------------总结------------------------------------------------------------------

总结,一个自定义的Object:

  • 在编写clone()方法的时候,默认的clone()方法行为,针对于StringBuffer和StringBuilder 类型是浅克隆(只要是对象类型,都是浅克隆)
  • 我们需要担心,“p.address1的值修改了,pclone.address1也跟着修改” 的这种情况!
  • 因为StringBuffer(StringBuilder)类型,在通过其自带的方法赋值的时候,是修改了原来的值(其内部维护的char[] value)!
  • 所以:一个自定义的Object,针对于StringBuffer(StringBuilder)类型,使用默认的clone()方法不可行。
  • 那么怎么办呢?嘿嘿,其实是可以针对StringBuffer(StringBuilder)类型,修改clone()方法:
    	@Override
    	public Person clone() throws CloneNotSupportedException {
    		Person p = (Person) super.clone();
    		// StringBuffer, StringBuilder没有自己的clone()方法,所以就重新new出来
    
    		p.address1 = new StringBuffer(this.address1);
    		p.address2 = new StringBuilder(this.address2);
    		
    		return p;
    	}
    
    


-------------------这样修改后的clone()的方法,再次测试之后---------------------------------------

先来看看debug截图:



通过debug可以发现:
  • 因为是new出新的对象,自然的 pclone.address1 id(37) pclone.address2 id(38) 和p.address1 id(24) p.address2 id(28) 所指向的对象不相同。
在修改了pclone.address1 pclone.address2之后,来看看控制台:

-------------after set-------------------
p:Person [age=180, height=190, name=郭美美不美, address1=中国北京, address2=美国纽约]
pclone:Person [age=18, height=162, name=郭美美, address1=中国北京!!!, address2=美国纽约......]









  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值