温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

如何解析Java语言的对象克隆特性

发布时间:2021-11-20 18:07:02 来源:亿速云 阅读:169 作者:柒染 栏目:编程语言

这篇文章将为大家详细讲解有关如何解析Java语言的对象克隆特性,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。

在Java中传值及引伸深度克隆的思考中,我们讲过引申到克隆技术Java中的所有对象都是Object类的子类。我们知道,Java是纯面向对象的程序设计语言。Java里,所有的类的***父类都是java.lang.Object类,也就是说,如果一个类没有显示 申明继承关系,它的父类默认就是java.lang.Object。

有一个很简单的方法可以证明这一点,我们写一个Test类,如下:

public class Test {       public void someMethod() {           super.clone();       }   }

里面调用了super.clone(),编译时并不报错。其实clone()方法为java.lang.Object类提供的一个 protected型方法。

对象克隆

本文通过介绍java.lang.Object#clone()方法来说明Java语言的对象克隆特性。

java.lang.Object#clone()方法由java.lang.Object加以实现,主要对对象本身加以克隆。

首先我们看看下面的例子:

public class TestClone {       public static void main(String[] args) {           MyClone myClone1 = new MyClone("clone1");                     MyClone myClone2 = (MyClone)myClone1.clone();                     if (myClone2 != null) {               System.out.println(myClone2.getName());               System.out.println("myClone2 equals myClone1: " + myClone2.equals(myClone1));           } else {               System.out.println("Clone Not Supported");           }       }   }   class MyClone {       private String name;       public MyClone(String name) {           this.name = name;       }             public String getName() {           return name;       }       public void setName(String name) {           this.name = name;       }             public Object clone() {           try {               return super.clone();           } catch (CloneNotSupportedException e) {               return null;           }       }

编译执行TestClone,打印出:

C:\clone>javac *.java   C:\clone>java TestClone   Clone Not Supported   C:\clone>

说明MyClone#clone()方法调用super.clone()时抛出了CloneNotSupportedException异常,不支持克隆。

为什么父类java.lang.Object里提供了clone()方法,却不能调用呢?

原来,Java语言虽然提供了这个方法,但考虑到安全问题, 一方面将clone()访问级别设置为protected型,以限制外部类访问;

另一方面,强制需要提供clone功能的子类实现java.lang.Cloneable接口,在运行期,JVM会检查调用clone()方法的 类,如果该类未实现java.lang.Cloneable接口,则抛出CloneNotSupportedException异常。

java.lang.Cloneable接口是一个空的接口,没有申明任何属性与方法。该接口只是告诉JVM,该接口的实现类需要开放“克隆”功能。

我们再将MyClone类稍作改变,让其实现Cloneable接口:

class MyClone implements Cloneable {       ...//其余不做改变   }    编译执行TestClone,打印出:    C:\clone>javac *.java   C:\clone>java TestClone   clone1   myClone2 equals myClone1: false   C:\clone>

根据结果,我们可以发现:

1,myClone1.clone()克隆了跟myClone1具有相同属性值的对象

2,但克隆出的对象myClone2跟myClone1不是同一个对象(具有不同的内存空间)

小结

如果要让一个类A提供克隆功能,该类必须实现java.lang.Cloneable接口,并重载 java.lang.Object#clone()方法。

public class A extends Cloneable {       public Object clone() {           try {               return super.clone();           } catch (CloneNotSupportedException e) {               //throw (new InternalError(e.getMessage()));               return null;           }       }   }

对象的深层次克隆

上例说明了怎么样克隆一个具有简单属性(String,int,boolean等)的对象。

但如果一个对象的属性类型是List,Map,或者用户自定义的其他类时,克隆行为是通过怎样的方式进行的?

很多时候,我们希望即使修改了克隆后的对象的属性值,也不会影响到原对象,这种克隆我们称之为对象的深层次克隆。怎么样实现对象的深层次克隆呢?

验证对象的克隆方式

为了验证对象的克隆方式,我们对上面的例子加以改进,如下(为了节省篇幅,我们省略了setter与getter方法):

public class TestClone {       public static void main(String[] args) {           //为克隆对象设置值            MyClone myClone1 = new MyClone("clone1");            myClone1.setBoolValue(true);            myClone1.setIntValue(100);                     //设置List值            List <Element>listValue = new ArrayList<Element>();            listValue.add(new Element("ListElement1"));            listValue.add(new Element("ListElement2"));            listValue.add(new Element("ListElement3"));            myClone1.setListValue(listValue);                     //设置Element值            Element element1 = new Element("element1");            myClone1.setElement(element1);                               //克隆            MyClone myClone2 = (MyClone)myClone1.clone();                     if (myClone2 != null) {                             //简单属性                System.out.println("myClone2.name=" + myClone2.getName()                        + " myClone2.boolValue=" + myClone2.isBoolValue()                        + " myClone2.intValue=" + myClone2.getIntValue() );                             //复合属性(List<Element>与Element)                List clonedList = myClone2.getListValue();                Element element2 = myClone2.getElement();                              System.out.println("myClone2.listValue.size():" + clonedList.size());                System.out.println("myClone2.element.equals(myClone1.element):" + element2.equals(element1));                System.out.println("myClone2.element.name:" + element2.getName());                             //下面我们测试一下myClone2.element是否等于myClone1.element               //以及myClone2.listValue是否等于myClone1.listValue               //为此,我们修改myClone2.element与myClone2.listValue,如果myClone1的相应值也跟着被修改了,则它们引用 的是同一个内存空间的变量,我们认为它们相等                              clonedList.add("ListElement4");                              System.out.println("myClone1.listValue.size():" + listValue.size());                              element2.setName("Element2");                System.out.println("myClone1.element.name:" + element1.getName());                          } else {                System.out.println("Clone Not Supported");            }                         }    }     class MyClone implements Cloneable {       private int intValue;       private boolean boolValue;       private String name;       private List <Element>listValue;       private Element element;        public MyClone(String name) {            this.name = name;        }         ...//setter与getter方法(略)   }    class Element implements Cloneable   {       private String name;             public Element (String name) {            this.name = name;        }         ...//setter与getter方法(略)   }

编译执行TestClone,打印出:

C:\clone>javac *.java   C:\clone>java TestClone   myClone2.name=clone1 myClone2.boolValue=true myClone2.intValue=100   myClone2.listValue.size():3   myClone2.element.equals(myClone1.element):true   myClone2.element.name:element1   myClone1.listValue.size():4   myClone1.element.name:Element2   myClone2 equals myClone1: false   C:\clone>

我们发现,对于对象里的List,Element等复合属性,super.clone()只是简单地赋值,没有采取克隆手段。也就是说,修改被克 隆后的对象值,会影响到原对象。

怎么进行深层次的克隆呢?

答案是,我们只能手动在重载的clone()方法里,对属性也分别采用克隆操作。当然条件是,属性类也得支持克隆操作

class MyClone implements Cloneable {        ...       public Object clone() {           try {                MyClone myClone = (MyClone)super.clone();               //分别对属性加以克隆操作                myClone.element = this.element.clone();                              myClone.listValue = new ArrayList();               for (Element ele:this.listValue) {                    myClone.listValue.add(ele.clone());                }                                         return myClone;            } catch (CloneNotSupportedException e) {               return null;            }        }        ...   }    //让Element类也支持克隆操作   class Element implements Cloneable   {        ...       public Element clone() {           try {               return (Element)super.clone();            } catch (CloneNotSupportedException e) {               return null;            }        }   }

深层次的克隆操作往往存在效率问题,尤其是需要让List,Map等集合类也支持深层次的克隆操作时。

结合范例,比较深入地介绍了Java语言的克隆属性,以及克隆的实现方法等。同时分析了深层次克隆的概念,实现,以及存在的问题等。

关于如何解析Java语言的对象克隆特性就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI