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@74a14482System.out.println(p1);// com.company.Person@74a14482System.out.println(p2);p1.setName("xxx");// xxxSystem.out.println(p1.getName());// xxxSystem.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;}@Overrideprotected 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;}@Overrideprotected 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@74a14482System.out.println(p1);// com.company.Person@1540e19dSystem.out.println(p2);p1.setName("xxx");// xxxSystem.out.println(p1.getName());// p1System.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;}@Overrideprotected 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@74a14482System.out.println(p1);// com.company.Person@1540e19dSystem.out.println(p2);p1.setName("xxx");p1.getAge().setAge(20);// xxxSystem.out.println(p1.getName());// com.company.Age@677327b6System.out.println(p1.getAge());// 20System.out.println(p1.getAge().getAge());// p1System.out.println(p2.getName());// com.company.Age@677327b6System.out.println(p2.getAge());// 20System.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;}@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}}
改造下Person的clone方法
@Overrideprotected 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@74a14482System.out.println(p1);// com.company.Person@1540e19dSystem.out.println(p2);p1.setName("xxx");p1.getAge().setAge(20);// xxxSystem.out.println(p1.getName());// com.company.Age@677327b6System.out.println(p1.getAge());// 20System.out.println(p1.getAge().getAge());// p1System.out.println(p2.getName());// com.company.Age@14ae5a5System.out.println(p2.getAge());// 10System.out.println(p2.getAge().getAge());}}
3、深拷贝 / 浅拷贝
浅拷贝: 指拷贝对象时仅仅拷贝对象本身(包括对象中的基本变量),而不拷贝对象包含的引用指向的对象。
- 深拷贝 :深拷贝不仅拷贝对象本身,而且拷贝对象包含的引用指向的所有对象。
- 上面的例子3里面,其实就是属于浅拷贝,对于clone方法来说,如果不对clone方法进行改造,那么默认的使用,都是浅拷贝。
- 上面的例子4里面,其实就是属于深拷贝
