1、引入传递
下面的例子,p1、p2内存地址一样,无论修改p1还是p2,另一个都会收到影响
public class Test {
public static void main(String[] args) {
Person p1 = new Person();
p1.setName("p1");
Person p2 = p1;
// 内存地址一样
// com.company.Person@74a14482
System.out.println(p1);
// com.company.Person@74a14482
System.out.println(p2);
p1.setName("xxx");
// xxx
System.out.println(p1.getName());
// xxx
System.out.println(p2.getName());
}
}
2、浅拷贝
所有的java类都继承的java.lang.Object,Object里面有个native clone()方法
protected native Object clone() throws CloneNotSupportedException;
Person.java 添加clone方法,发现上述代码运行会报错,CloneNotSupportedException
public class Person {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
查看源码可知:native关键字修饰的方法,代表这个方法实现体被调用,是告知 jvm去调用非java代码编写的实现体,例如C语言编写的等。而 jvm能否去调用这个实现体,也就是根据咱们是否有实现了Cloneable这个接口做为标记
public class Person implements Cloneable{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
运行结果如下
public class Test {
public static void main(String[] args) throws CloneNotSupportedException {
Person p1 = new Person();
p1.setName("p1");
Person p2 = (Person) p1.clone();
// 内存地址一样
// com.company.Person@74a14482
System.out.println(p1);
// com.company.Person@1540e19d
System.out.println(p2);
p1.setName("xxx");
// xxx
System.out.println(p1.getName());
// p1
System.out.println(p2.getName());
}
}
3、深拷贝
Person中还有一个Age类,Person实现了Cloneable接口,但是Age还没有
public class Person implements Cloneable{
private String name;
private Age age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Age getAge() {
return age;
}
public void setAge(Age age) {
this.age = age;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
验证结果:Person是不同内存地址,但是Age内存地址一样
public class Test {
public static void main(String[] args) throws CloneNotSupportedException {
Person p1 = new Person();
p1.setName("p1");
Age age = new Age();
age.setAge(10);
p1.setAge(age);
Person p2 = (Person) p1.clone();
// 内存地址一样
// com.company.Person@74a14482
System.out.println(p1);
// com.company.Person@1540e19d
System.out.println(p2);
p1.setName("xxx");
p1.getAge().setAge(20);
// xxx
System.out.println(p1.getName());
// com.company.Age@677327b6
System.out.println(p1.getAge());
// 20
System.out.println(p1.getAge().getAge());
// p1
System.out.println(p2.getName());
// com.company.Age@677327b6
System.out.println(p2.getAge());
// 20
System.out.println(p2.getAge().getAge());
}
}
Age也实现Cloneable接口,但是上述验证代码Age还是一样的内存地址
public class Age implements Cloneable{
private int age;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
改造下Person的clone方法
@Override
protected Object clone() throws CloneNotSupportedException {
Person person = (Person) super.clone();
person.age = (Age) age.clone();
return person;
// return super.clone();
}
验证结果如下:两个age已经是不同的内存地址了,这里就是深拷贝
public class Test {
public static void main(String[] args) throws CloneNotSupportedException {
Person p1 = new Person();
p1.setName("p1");
Age age = new Age();
age.setAge(10);
p1.setAge(age);
Person p2 = (Person) p1.clone();
// 内存地址一样
// com.company.Person@74a14482
System.out.println(p1);
// com.company.Person@1540e19d
System.out.println(p2);
p1.setName("xxx");
p1.getAge().setAge(20);
// xxx
System.out.println(p1.getName());
// com.company.Age@677327b6
System.out.println(p1.getAge());
// 20
System.out.println(p1.getAge().getAge());
// p1
System.out.println(p2.getName());
// com.company.Age@14ae5a5
System.out.println(p2.getAge());
// 10
System.out.println(p2.getAge().getAge());
}
}
3、深拷贝 / 浅拷贝
浅拷贝: 指拷贝对象时仅仅拷贝对象本身(包括对象中的基本变量),而不拷贝对象包含的引用指向的对象。
- 深拷贝 :深拷贝不仅拷贝对象本身,而且拷贝对象包含的引用指向的所有对象。
- 上面的例子3里面,其实就是属于浅拷贝,对于clone方法来说,如果不对clone方法进行改造,那么默认的使用,都是浅拷贝。
- 上面的例子4里面,其实就是属于深拷贝