学习Java语言程序设计时,接口一章提到cloneable,又联想到关于对象的复制相关问题,于是就把两者结合在一起,进行一个简单的辨析。
class Employee implements Cloneable{
String name;
int id;
Address address;
public Employee(String name,int id,Address address){
this.name=name;
this.id=id;
this.address=address;
}
public void setId(int id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
@Override
public String toString() {
return "Employee{" +
"name='" + name + '\'' +
", id=" + id +
", address=" + address +
'}';
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
在Employee类中定义了String类型的name,int类型的id,和一个引用数据类型型Address类的address对象。还声明了getter,setter方法来对Employee对象的属性进行修改。
class myAddress implements Cloneable{
String streetName;
int streetId;
public myAddress(String streetName,int streetId){
this.streetName=streetName;
this.streetId=streetId;
}
public void setStreetId(int streetId) {
this.streetId = streetId;
}
public void setStreetName(String streetName) {
this.streetName = streetName;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
在该Address类中实现了对于String类型的streetName和int类型的streetId的定义,达到后续对于属性修改的目的。
public class _demo {
public static void main(String[] args) throws CloneNotSupportedException {
Employee e1=new Employee("aaa",12,new Address(111,"aaaaa"));
System.out.println(e1);
Employee e2=e1;
System.out.println(e2);
e2.setId(11);
e2.setName("bbb");
e2.getAddress().setStreetid(112);
e2.getAddress().setStreetname("bbbbb");
System.out.println(e1);
System.out.println(e2);
Employee e22=(Employee) e1.clone();
System.out.println(e22);
e22.setId(10);
e22.setName("ccc");
e22.getAddress().setStreetid(132);
e22.getAddress().setStreetname("ccccc");
System.out.println(e1);
System.out.println(e2);
System.out.println(e22);
}
在主函数中声明了一个引用e1,其指向一个这样的对象,其属性值分别为(按照name,id,streetName,streetId的顺序) aaa,12,aaaaaa,111。
之后声明另一个引用e2,和e1指向堆中的同一个对象。如果在e2中调用Empoyee类中的setter,getter函数对属性值进行修改,此时打印出e1,e2,会发现两者的属性值同步改变,即属性值都变成e2修改后的值--bbb,11,bbbbb,112。因为e2中拿到的是e1引用所指向的地址,直接对堆中的对象进行修改,结果就是从e1,e2拿到的都是修改后的对象。
但是再声明一个e22引用,其不同之处在于e22是由e1通过Cloneable中的clone复制得到的,对与基本数据类型,e1直接是把属性对应的数值拷贝给e22;对于引用数据类型,则只是把地址拷贝给e22,此时就会出现e1,e2,e22中的拿到的其实是堆中的同一个地址对象。此时如果e22对name,id属性改变,只是会改变自身的这些属性值 ,对于e1,e2的值不会产生改变。但是若是堆address属性改变,就会造成三者的属性同时发生改变。
对应的main函数中的输出如下:
// Employee{name='aaa', id=12, address=Address{streetid=111, streetname='aaaaa'}}
// Employee{name='aaa', id=12, address=Address{streetid=111, streetname='aaaaa'}}
// Employee{name='bbb', id=11, address=Address{streetid=112, streetname='bbbbb'}}
// Employee{name='bbb', id=11, address=Address{streetid=112, streetname='bbbbb'}}
// Employee{name='bbb', id=11, address=Address{streetid=112, streetname='bbbbb'}}
// Employee{name='bbb', id=11, address=Address{streetid=132, streetname='ccccc'}}
// Employee{name='bbb', id=11, address=Address{streetid=132, streetname='ccccc'}}
// Employee{name='ccc', id=10, address=Address{streetid=132, streetname='ccccc'}}
如有错误,欢迎指正!