类似的文章其实已经很多了,我只是记录下自己的理解
浅拷贝:基本类型完全拷贝值传递,引用类型只是引用的传递(hashcode一致)
深拷贝:基本类型完全拷贝值传递,引用类型完全拷贝创建新对象(hashcode不同)
通过Object.clone()实现时需要注意以下2点,否则抛出CloneNotSupportedException
实现Cloneable接口
重写clone()方法
浅拷贝(Shallow Copy)
被拷贝对象实现Cloneable接口,并且重写clone()方法即可
class Kid {
private String kname;
public String getKname() {
return kname;
}
public void setKname(String kname) {
this.kname = kname;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((kname == null) ? 0 : kname.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Kid other = (Kid) obj;
if (kname == null) {
if (other.kname != null)
return false;
} else if (!kname.equals(other.kname))
return false;
return true;
}
}
class BasicObj implements Cloneable {
private String name;
private Kid kid;
public BasicObj(String name, Kid kid) {
super();
this.name = name;
this.kid = kid;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Kid getKid() {
return kid;
}
public void setKid(Kid kid) {
this.kid = kid;
}
}
public class CopyTest {
public static void main(String[] args) throws CloneNotSupportedException {
Kid k = new Kid();
k.setKname("Apple");
BasicObj a = new BasicObj("Hello", k);
BasicObj b = (BasicObj) a.clone();
System.out.println(a == b);
System.out.println("a.id = " + a.getName() + ", b.id = " + b.getName());
System.out.println("a.kid.name = " + a.getKid().getKname() + ", b.kid.name = " + b.getKid().getKname());
System.out.println("a.kid.hashcode = " + a.getKid().hashCode() + ", b.kid.hashcode = " + b.getKid().hashCode());
System.out.println("---------------");
//改变了引用对象的值
k.setKname("Lemon");
a.setKid(k);
//改变本地类型的值
a.setName("World");
System.out.println("a.id = " + a.getName() + ", b.id = " + b.getName());
System.out.println("a.kid.name = " + a.getKid().getKname() + ", b.kid.name = " + b.getKid().getKname());
System.out.println("a.kid.hashcode = " + a.getKid().hashCode() + ", b.kid.hashcode = " + b.getKid().hashCode());
}
}
输出
false
a.id = Hello, b.id = Hello
a.kid.name = Apple, b.kid.name = Apple
a.kid.hashcode = 63476569, b.kid.hashcode = 63476569
---------------
a.id = World, b.id = Hello
a.kid.name = Lemon, b.kid.name = Lemon
a.kid.hashcode = 73304818, b.kid.hashcode = 73304818
改变a的基本类型,b不变
改变a的引用类型,b改变
深拷贝(Deep Copy)
被拷贝对象中的对引用类型需要实现Cloneable接口,且重写clone()方法(类似递归操作,直至拷贝到基本类型为止)
//引用类型对象实现了Cloneable接口
class Kid implements Cloneable {
private String kname;
public String getKname() {
return kname;
}
public void setKname(String kname) {
this.kname = kname;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((kname == null) ? 0 : kname.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Kid other = (Kid) obj;
if (kname == null) {
if (other.kname != null)
return false;
} else if (!kname.equals(other.kname))
return false;
return true;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
class BasicObj implements Cloneable {
private String name;
private Kid kid;
public BasicObj(String name, Kid kid) {
super();
this.name = name;
this.kid = kid;
}
//改造clone方法,对引用类型对象Kid进行clone操作
@Override
protected Object clone() throws CloneNotSupportedException {
BasicObj bo = new BasicObj(name, kid);
bo.kid = (Kid) this.kid.clone();
return bo;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Kid getKid() {
return kid;
}
public void setKid(Kid kid) {
this.kid = kid;
}
}
public class CopyTest {
public static void main(String[] args) throws CloneNotSupportedException {
Kid k = new Kid();
k.setKname("Apple");
BasicObj a = new BasicObj("Hello", k);
BasicObj b = (BasicObj) a.clone();
System.out.println(a == b);
System.out.println("a.id = " + a.getName() + ", b.id = " + b.getName());
System.out.println("a.kid.name = " + a.getKid().getKname() + ", b.kid.name = " + b.getKid().getKname());
System.out.println("a.kid.hashcode = " + a.getKid().hashCode() + ", b.kid.hashcode = " + b.getKid().hashCode());
System.out.println("---------------");
//改变了引用对象的值
k.setKname("Lemon");
a.setKid(k);
//改变本地类型的值
a.setName("World");
System.out.println("a.id = " + a.getName() + ", b.id = " + b.getName());
System.out.println("a.kid.name = " + a.getKid().getKname() + ", b.kid.name = " + b.getKid().getKname());
System.out.println("a.kid.hashcode = " + a.getKid().hashCode() + ", b.kid.hashcode = " + b.getKid().hashCode());
}
}
输出
false
a.id = Hello, b.id = Hello
a.kid.name = Apple, b.kid.name = Apple
a.kid.hashcode = 63476569, b.kid.hashcode = 63476569
---------------
a.id = World, b.id = Hello
a.kid.name = Lemon, b.kid.name = Apple
a.kid.hashcode = 73304818, b.kid.hashcode = 63476569
改变a的基本类型,b不变
改变a的引用类型,b不变