参考地址:https://blog.csdn.net/u011679955/article/details/52736379
在Javd中所有的传参都是值传递,并没有引用传递。有些方法参数是一个对象,也是值传递,传递的是对象的引用地址,这个地址指向堆中的一个对象,并没有传递一个对象。但是,拿到这个地址,传入对象的属性就可以被改变。不想对象的内容被方法改变,就是创建一个和原来对象一样的临时对象,进行参数传递。可以使用clone方法进行对象的复制。
clone方法主要分成两步:
1.对象所属的类实现Cloneable接口,这个接口就像序列化接口一样,标识这是一个可以克隆的对象
2.方法中使用它, 如person.clone()
clone分为浅克隆和深克隆:因为克隆的对象和原来的对象属性一样,原对象中属性是引用地址,克隆的也是引用地址,并不是克隆引用地址指向的对象。当这个引用地址指向的对象内容改变,所有的引用这个对象的内容也就改变了,这就是浅克隆。比如 a b c三个对象,b是a的一个对象属性,c是a的克隆对象,当a中b对象发生了改变,c中的b对象也发生改变。与浅克隆相对应的就是深克隆,深克隆是将对象属性也进行克隆,不再是直接复制原对象的引用地址。主要是在属性对象所在的类中也实现Cloneable接口,再在要克隆类的clone方法中指明属性对象也进行克隆,将引用地址改变。比如a b c三个对象,b是a的一个对象属性,c是a的克隆对象。b也实现cloneable接口,覆写clone方法,a在clone中指定 a=super.clone();a.b=B.clone()
public class Person implements Cloneable {
private int age ;;
private String name;
private String sex;
public Person() {
}
public Person(int age, String name, String sex) {
this.age = age;
this.name = name;
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
@Override
public String toString() {
return "Person [age=" + age + ", name=" + name + ", sex=" + sex + "]";
}
@Override
public Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return null;
}
}
public class Group implements Cloneable{
private String groupName;
private String groupId;
private Person person;
public Group() {
}
public Group(String groupName, String groupId, Person person) {
super();
this.groupName = groupName;
this.groupId = groupId;
this.person = person;
}
public String getGroupName() {
return groupName;
}
public void setGroupName(String groupName) {
this.groupName = groupName;
}
public String getGroupId() {
return groupId;
}
public void setGroupId(String groupId) {
this.groupId = groupId;
}
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
@Override
public String toString() {
return "Group [groupName=" + groupName + ", groupId=" + groupId + ", person=" + person + "]";
}
public Object clone() {
Group group = null;
try {
group = (Group)super.clone();
// 深克隆,将属性person也进行克隆,Person要实现Cloneable
group.person = (Person) person.clone();
return group;
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return group;
}
}
public class ThinkInJava {
/**
* clone()方法,是在堆中复制一个对象,就像new一个对象一样,这个对象属性和原来的对象一样,只是栈中的引用地址变了
* 想使用clone(),必须实现Cloneable接口,Cloneable是个标志,就像序列化一样
* clone()分为浅克隆和深克隆,因为克隆的对象和原来的对象属性一样。如果原对象中属性是引用地址,克隆的也是引用地址,没有克隆引用地址指向的对象
* 当这个引用地址指向的对象内容改变,所有的引用这个对象的内容也就改变了,这就是浅克隆。
* 比如 a b c三个对象,a对象中有b的对象属性,c是a的克隆对象,当a中b对象发生了改变,c中的b对象也发生改变
* 与浅克隆相对应的就是深克隆,深克隆是在引用对象中也实现clone方法,再在对象中指明引用对象也克隆,将引用地址改变
* 如 a = super.clone() a.b=b.clone()
*
*/
@Test
public void testBean() {
Person p1 = new Person(12, "p1", "man");
Person p2 =(Person) p1.clone();
System.out.println("Person的String引用地址是否相同"+p1.getName().equals(p2.getName()));
p1.setName("p2");
System.out.println("Person的String引用地址是否相同"+p1.getName().equals(p2.getName()));
System.out.println(p1.toString());
System.out.println(p2.toString());
}
@Test
public void testGroup() {
Person p1 = new Person(12, "p1", "man");
Group g1 = new Group("g1", "g1", p1);
Group g2 = (Group)g1.clone();
System.out.println("Group的Person引用地址是否相同"+g1.getPerson().equals(g2.getPerson()));
p1.setName("p2");
System.out.println("Group的Person引用地址是否相同"+g1.getPerson().equals(g2.getPerson()));
System.out.println(g1.toString());
System.out.println(g2.toString());
}
}
testBean运行后结果是这个:
Person的String引用地址是否相同true
Person的String引用地址是否相同false
Person [age=12, name=p2, sex=man]
Person [age=12, name=p1, sex=man]
好像和我说的引用地址没变冲突,其实没有冲突。主要是string类型的特殊造成的,String类型是final的不可变的,当string 的发生变化时它的引用地址就会发生变化,指向一个新的引用地址。在上面的结果中,第一个true说明刚刚克隆完p1对象,p1和p2的string引用地址是相同的,当p1的name字段发生改变,它的引用地址发生了改变,原来的引用废弃了,结果就是p2,p1的引用还是原来的结果是p1,他们的引用地址不同了
属性字段是对象的克隆,属性对象没有实现克隆接口,testGroup运行后:
Group的Person引用地址是否相同true
Group的Person引用地址是否相同true
Group [groupName=g1, groupId=g1, person=Person [age=12, name=p2, sex=man]]
Group [groupName=g1, groupId=g1, person=Person [age=12, name=p2, sex=man]]
发现g1 g2中p1对象一样,他们的属性person指向同一个对象,p1变了,他们的person属性发生变化,这就是浅克隆
下面是深克隆,属性对象实现了克隆接口,Group中指出person属性也进行对象克隆,将引用地址改变,结果如下:
Group的Person引用地址是否相同false
Group的Person引用地址是否相同false
Group [groupName=g1, groupId=g1, person=Person [age=12, name=p2, sex=man]]
Group [groupName=g1, groupId=g1, person=Person [age=12, name=p1, sex=man]]