在自定义类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=美国纽约......]
p:Person [age=180, height=190, name=郭美美不美, address1=中国北京, address2=美国纽约]
pclone:Person [age=18, height=162, name=郭美美, address1=中国北京!!!, address2=美国纽约......]