1、引入传递

  • 下面的例子,p1、p2内存地址一样,无论修改p1还是p2,另一个都会收到影响

    1. public class Test {
    2. public static void main(String[] args) {
    3. Person p1 = new Person();
    4. p1.setName("p1");
    5. Person p2 = p1;
    6. // 内存地址一样
    7. // com.company.Person@74a14482
    8. System.out.println(p1);
    9. // com.company.Person@74a14482
    10. System.out.println(p2);
    11. p1.setName("xxx");
    12. // xxx
    13. System.out.println(p1.getName());
    14. // xxx
    15. System.out.println(p2.getName());
    16. }
    17. }

    2、浅拷贝

  • 所有的java类都继承的java.lang.Object,Object里面有个native clone()方法

    1. protected native Object clone() throws CloneNotSupportedException;
  • Person.java 添加clone方法,发现上述代码运行会报错,CloneNotSupportedException

    1. public class Person {
    2. private String name;
    3. public String getName() {
    4. return name;
    5. }
    6. public void setName(String name) {
    7. this.name = name;
    8. }
    9. @Override
    10. protected Object clone() throws CloneNotSupportedException {
    11. return super.clone();
    12. }
    13. }
  • 查看源码可知:native关键字修饰的方法,代表这个方法实现体被调用,是告知 jvm去调用非java代码编写的实现体,例如C语言编写的等。而 jvm能否去调用这个实现体,也就是根据咱们是否有实现了Cloneable这个接口做为标记

    1. public class Person implements Cloneable{
    2. private String name;
    3. public String getName() {
    4. return name;
    5. }
    6. public void setName(String name) {
    7. this.name = name;
    8. }
    9. @Override
    10. protected Object clone() throws CloneNotSupportedException {
    11. return super.clone();
    12. }
    13. }
  • 运行结果如下

    1. public class Test {
    2. public static void main(String[] args) throws CloneNotSupportedException {
    3. Person p1 = new Person();
    4. p1.setName("p1");
    5. Person p2 = (Person) p1.clone();
    6. // 内存地址一样
    7. // com.company.Person@74a14482
    8. System.out.println(p1);
    9. // com.company.Person@1540e19d
    10. System.out.println(p2);
    11. p1.setName("xxx");
    12. // xxx
    13. System.out.println(p1.getName());
    14. // p1
    15. System.out.println(p2.getName());
    16. }
    17. }

    3、深拷贝

  • Person中还有一个Age类,Person实现了Cloneable接口,但是Age还没有

    1. public class Person implements Cloneable{
    2. private String name;
    3. private Age age;
    4. public String getName() {
    5. return name;
    6. }
    7. public void setName(String name) {
    8. this.name = name;
    9. }
    10. public Age getAge() {
    11. return age;
    12. }
    13. public void setAge(Age age) {
    14. this.age = age;
    15. }
    16. @Override
    17. protected Object clone() throws CloneNotSupportedException {
    18. return super.clone();
    19. }
    20. }
  • 验证结果:Person是不同内存地址,但是Age内存地址一样

    1. public class Test {
    2. public static void main(String[] args) throws CloneNotSupportedException {
    3. Person p1 = new Person();
    4. p1.setName("p1");
    5. Age age = new Age();
    6. age.setAge(10);
    7. p1.setAge(age);
    8. Person p2 = (Person) p1.clone();
    9. // 内存地址一样
    10. // com.company.Person@74a14482
    11. System.out.println(p1);
    12. // com.company.Person@1540e19d
    13. System.out.println(p2);
    14. p1.setName("xxx");
    15. p1.getAge().setAge(20);
    16. // xxx
    17. System.out.println(p1.getName());
    18. // com.company.Age@677327b6
    19. System.out.println(p1.getAge());
    20. // 20
    21. System.out.println(p1.getAge().getAge());
    22. // p1
    23. System.out.println(p2.getName());
    24. // com.company.Age@677327b6
    25. System.out.println(p2.getAge());
    26. // 20
    27. System.out.println(p2.getAge().getAge());
    28. }
    29. }
  • Age也实现Cloneable接口,但是上述验证代码Age还是一样的内存地址

    1. public class Age implements Cloneable{
    2. private int age;
    3. public int getAge() {
    4. return age;
    5. }
    6. public void setAge(int age) {
    7. this.age = age;
    8. }
    9. @Override
    10. protected Object clone() throws CloneNotSupportedException {
    11. return super.clone();
    12. }
    13. }
  • 改造下Person的clone方法

    1. @Override
    2. protected Object clone() throws CloneNotSupportedException {
    3. Person person = (Person) super.clone();
    4. person.age = (Age) age.clone();
    5. return person;
    6. // return super.clone();
    7. }
  • 验证结果如下:两个age已经是不同的内存地址了,这里就是深拷贝

    1. public class Test {
    2. public static void main(String[] args) throws CloneNotSupportedException {
    3. Person p1 = new Person();
    4. p1.setName("p1");
    5. Age age = new Age();
    6. age.setAge(10);
    7. p1.setAge(age);
    8. Person p2 = (Person) p1.clone();
    9. // 内存地址一样
    10. // com.company.Person@74a14482
    11. System.out.println(p1);
    12. // com.company.Person@1540e19d
    13. System.out.println(p2);
    14. p1.setName("xxx");
    15. p1.getAge().setAge(20);
    16. // xxx
    17. System.out.println(p1.getName());
    18. // com.company.Age@677327b6
    19. System.out.println(p1.getAge());
    20. // 20
    21. System.out.println(p1.getAge().getAge());
    22. // p1
    23. System.out.println(p2.getName());
    24. // com.company.Age@14ae5a5
    25. System.out.println(p2.getAge());
    26. // 10
    27. System.out.println(p2.getAge().getAge());
    28. }
    29. }

    3、深拷贝 / 浅拷贝

  • 浅拷贝: 指拷贝对象时仅仅拷贝对象本身(包括对象中的基本变量),而不拷贝对象包含的引用指向的对象。

  • 深拷贝 :深拷贝不仅拷贝对象本身,而且拷贝对象包含的引用指向的所有对象。
  • 上面的例子3里面,其实就是属于浅拷贝,对于clone方法来说,如果不对clone方法进行改造,那么默认的使用,都是浅拷贝。
  • 上面的例子4里面,其实就是属于深拷贝