0
点赞
收藏
分享

微信扫一扫

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截图:

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

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


通过debug可以发现:

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



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


debug截图:




java中的clone()方法的研究---(6)如何编写正确的clone()方法:StringBuffer,StringBuilder_浅克隆_02


通过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源代码的区别:---------------------------------------




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




  • 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截图:



java中的clone()方法的研究---(6)如何编写正确的clone()方法:StringBuffer,StringBuilder_浅克隆_04





通过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=美国纽约......]















举报

相关推荐

Git clone的使用方法

0 条评论