• Java的clone()方法


    1. clone方法简介

    clone方法返回与当前对象的一个副本对象。可以通过操作副本对象而不影响当前对象。

    使用clone方法需要实现Cloneable接口。并重写Object方法中的clone方法。

    需要注意的是在clone在Object中是project修饰符。因为所有类都是Object的子类,所以如果不实现clone方法,在类中可以直接使用父类的clone方法,但是其对象在别的类中不能调用clone方法。所以必须重写clone方法。

    如果不实现Cloneable接口,只重写clone方法,调用则会抛出异常。

    Stu类未实现Cloneable接口所以抛出异常

    2. 浅克隆与深克隆

    2.1 浅克隆

    看下面一个例子

     1 import java.util.Arrays;
     2 import java.util.HashSet;
     3 import java.util.Scanner;
     4 import java.util.Set;
     5 
     6 public class Test {
     7     
     8     public static void main(String[] args) throws CloneNotSupportedException {
     9         Stu stu = new Stu();
    10         stu.name = "Tom";
    11         Stu stu1;
    12         stu1 = stu;
    13         System.out.println(stu==stu1);
    14         stu1.name = "LiMing";
    15         System.out.println("stu:"+stu.name+" stu1:"+stu1.name);
    16         stu1 = (Stu) stu.clone();
    17         System.out.println(stu==stu1);
    18         stu1.name = "Tom";
    19         System.out.println("stu:"+stu.name+" stu1:"+stu1.name);
    20     }
    21 
    22 }
    23 class Stu implements Cloneable{
    24     String name;
    25     @Override
    26     protected Object clone() throws CloneNotSupportedException {
    27         // TODO Auto-generated method stub
    28         return super.clone();
    29     }
    30     
    31 }

    Stu类实现了Cloneable接口,并且重写了clone方法。

    首先设stu1变量值等于stu,我们都知道stu1直接指向stu的地址。所以测试stu1==stu时,结果为true,说明两个地址相同。同时改变stu1的name值为“LiMing”,stu的name值也改为“LiMimg”。

    设stu1变量值等于stu.clone(),这时stu1的指向stu对象副本的地址,测试stu1==stu,结果为false,说明两个地址不同。改变stu1的name值为"Tom",stu因为指向的对象与stu1的指向的对象不同,因此stu的name值并未改变。

    测试结果

    2.2 深克隆

    考虑下面这种情况

    学生类包含笔类,这时在使用clone方法。

     1 public class Test {
     2     
     3     public static void main(String[] args) throws CloneNotSupportedException {
     4         Stu stu = new Stu();
     5         stu.name = "Tom";
     6         stu.pen.name = "A";
     7         Stu stu1;
     8         stu1 = (Stu) stu.clone();
     9         System.out.println(stu1.pen==stu.pen);
    10         stu1.pen.name = "B";
    11         System.out.println("stu1:"+stu1.pen.name+"|stu:"+stu.pen.name);
    12     }
    13 
    14 }
    15 class Stu implements Cloneable{
    16     String name;
    17     Pen pen = new Pen();
    18     @Override
    19     protected Object clone() throws CloneNotSupportedException {
    20         // TODO Auto-generated method stub
    21         return super.clone();
    22     }
    23     
    24 }
    25 class Pen{
    26     String name;
    27 }

    发现此时stu1.pen的地址与stu.pen的地址相同。所以改变stu1.pen.name的值,stu.pen.name的值也发生了相应的改变。这是因为对于引用类型,clone方法只克隆引用类型的地址。这时就用到了深克隆。

    测试结果

    深克隆:

     1 public class Test {
     2     
     3     public static void main(String[] args) throws CloneNotSupportedException {
     4         Stu stu = new Stu();
     5         stu.name = "Tom";
     6         stu.pen.name = "A";
     7         Stu stu1;
     8         stu1 = (Stu) stu.clone();
     9         System.out.println(stu1.pen==stu.pen);
    10         stu1.pen.name = "B";
    11         System.out.println("stu1:"+stu1.pen.name+"|stu:"+stu.pen.name);
    12     }
    13 
    14 }
    15 class Stu implements Cloneable{
    16     String name;
    17     Pen pen = new Pen();
    18     @Override
    19     protected Object clone() throws CloneNotSupportedException {
    20         // TODO Auto-generated method stub
    21         Stu temp = (Stu) super.clone();
    22         temp.pen = (Pen) pen.clone();
    23         return temp;
    24     }
    25     
    26 }
    27 class Pen implements Cloneable{
    28     String name;
    29     @Override
    30     protected Object clone() throws CloneNotSupportedException {
    31         // TODO Auto-generated method stub
    32         return super.clone();
    33     }
    34 }

    此时Pen类也重写了Cloneable方法。同时在重写Stu类的clone方法时先克隆Pen,在返回temp,这样temp中的pen指向克隆后的地址。

    运行结果stu1.pen的地址与stu.pen的地址不在相同,改变stu1.pen.name的值而stu.pen.name的值不在改变。stu1.pen对象是一个全新的副本。

    测试结果:

  • 相关阅读:
    C#路径中获取文件全路径、目录、扩展名、文件名称
    c#FTP应用---windows iis
    c#FTP应用---FileZilla Server
    在VS2010中使用Git管理源代码
    ABB机器人---PCSDK简介
    几款软件需求分析工具
    快速排序
    springmvc和struts2的区别比较
    Struts中ActionContext和ServletActionContext的比较
    设计模式--适配器模式
  • 原文地址:https://www.cnblogs.com/lolybj/p/9738946.html
Copyright © 2020-2023  润新知