精华内容
下载资源
问答
  • Cloneable

    2019-09-18 13:35:01
    Cloneable接口:是一个标记型接口,内部没有任何方法或属性的定义,这个标记仅针对Object类的clone()方法,如果没有实现这个接口去调用clone()方法,会抛出CloneNotSupportedException。 浅拷贝与深拷贝 ...
    • Cloneable接口:是一个标记型接口,内部没有任何方法或属性的定义,这个标记仅针对Object类的clone()方法,如果没有实现这个接口去调用clone()方法,会抛出CloneNotSupportedException。

       

    • 浅拷贝与深拷贝

    (1)浅拷贝:只拷贝对象和对象基本类型变量,引用类型变量指向同一个地址

    (2)深拷贝:拷贝对象、对象基本类型变量,引用类型变量重新创建指向新地址

    public class Person implements Cloneable {
        //姓名
        private String name;
        //生日
        private Date birthday;
    
        public Person() {
        }
    
        public Person(String name, Date birthday) {
            this.name = name;
            this.birthday = birthday;
        }
    
        protected void systemOut() {
            System.out.println("打印姓名:" + name + "出生日期:" + birthday);
        }
    
        @Override
        public Object clone() {
            Person person = null;
            try {
                //这里使用Object的clone方法(该方法为native方法)
                person = (Person) super.clone();
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
            }
            //如果没有对birthday这种引用类型单独处理,clone出来的对象中该属性与原对象指向同一个地址,就是浅拷贝,否则为深拷贝
             person.birthday = (Date) this.getBirthday().clone();
            return person;
        }
    
    
        public static void main(String[] args) throws CloneNotSupportedException {
            Date now = new Date();
            String name = "www";
            Person person = new Person(name, now);
            person.systemOut();
            System.out.println("/**===============================*/");
            Person person1 = (Person) person.clone();
            person1.systemOut();
            System.out.println("/**===============================*/");
            //浅拷贝导致两个person对象中的生日属性指向了同一个对象的,如果该对象做修改,两个对象都会变化
            now.setTime(1000);
            name = "com";//Strin虽然是引用类型,修改的时候会从字符串池中重新生成新的字符串,原味的对象保持不变,不会打印com
            person.systemOut();
            person1.systemOut();
            //两个person的类类型肯定是相同的,只创建了一个Class<Person>
            System.out.println(person.getClass() == person1.getClass());
            System.out.println(person == person1);//false
            System.out.println(person.getBirthday() == person1.getBirthday());//false
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public Date getBirthday() {
            return birthday;
        }
    
        public void setBirthday(Date birthday) {
            this.birthday = birthday;
        }
    
        @Override
        public String toString() {
            return "Person{" +
                    "name='" + name + '\'' +
                    ", birthday=" + birthday +
                    '}';
        }
    }

    浅拷贝的结果:两个Person对象的birthday都被改变了

    深拷贝的结果:两个birthday,互相不影响

    展开全文
  • var cloneable = require ( 'cloneable-readable' ) var fs = require ( 'fs' ) var pump = require ( 'pump' ) var stream = cloneable ( fs . createReadStream ( './package.json' ) ) pump ( stream . clone ( )...
  • U10316024_HW_15_10 类 MyStack 实现 Cloneable 并使用深循环
  • Java集合03 - Cloneable

    2020-12-10 21:18:53
    1.Cloneable是什么 Cloneable和Serializable接口一样,本质上都是一种标志性接口,无具体实现,意在告知JVM此类可实现克隆功能。当程序中想要使用一个对象的clone方法,仅仅用public重写基类clone方法还不够,还要...

    目录

    1.Cloneable是什么

    2.clone方法的追根溯源

    3.深浅拷贝

    4.如何实现深拷贝

         4.1 手动为引用类型赋值

         4.2 使用对象流进行深拷贝


    笔者JDK版本:1.8.0_202

    1.Cloneable是什么

           Cloneable和Serializable接口一样,本质上都是一种标志性接口,无具体实现,意在告知JVM此类可实现克隆功能。当程序中想要使用一个对象的clone方法,仅仅用public重写基类clone方法还不够,还要实现Cloneable接口,否则会抛出CloneNotSupportedException异常。

    2.clone方法的追根溯源

           在Java Object类中默认提供了clone方法:

           源码上的一大段注释翻译过来说了以下几件事(第5点不是源码里写的,作为clone的特点也列在这里):

           (1)重写clone方法原则(官方推荐这么做,为了编码规范听官方的准没错)

                    x.clone != x结果为true;

                    x.clone().getClass()==x.getClass()结果为true;

                    x.clone().equals(x)结果为true;

           (2)clone为浅拷贝:基本数据类型拷贝值,引用数据类型拷贝其引用地址(String特殊一点,拷贝的虽是引用,但在修改的时候会生成新的字符串)

           (3)不实现Cloneable接口使用clone方法会抛出CloneNotSupportedException异常(数组默认实现Cloneable接口,clone方法返回的类型是数组类型)

           (4)Object对象本身并不实现Cloneable接口,因此在Object对象上调用clone方法将会抛出运行时异常。

           (5)用clone方法创建对象并不会调用任何构造函数。

    3.深浅拷贝

           在阐述这个问题之前,我们需要先回忆一下Java创建对象的四种方式:1.new;2.Java反射机制的newInstance方法;3.反序列化;4.调用clone方法。在源码注释中我们也看到其对clone方法的解释为浅拷贝,那么什么是浅拷贝呢?请看如下的例子:

    public static void main(String[] args) {
            ArrayList<Integer> list = new ArrayList<>();
            list.add(1);
            ArrayList cloneList = (ArrayList)list.clone();
            System.out.println("修改实体数据前");
            System.out.println("原集合:"+list);
            System.out.println("克隆集合:"+cloneList);
            System.out.println("修改实体数据后");
            list.set(0,2);
            System.out.println("原集合:"+list);
            System.out.println("克隆集合:"+cloneList);
        }
    }

           创建一个ArrayList集合,放入一个基本数据类型1,调用其克隆方法复制一个ArrayList集合,改变原集合数据后发现对克隆集合数据并不会发生影响。

    public class CloneInfo  {
        private  String userName;
        private  String passWord;
        public String getUserName() {
            return userName;
        }
        public void setUserName(String userName) {
            this.userName = userName;
        }
        public String getPassWord() {
            return passWord;
        }
        public void setPassWord(String passWord) {
            this.passWord = passWord;
        }
    }
    public static void main(String[] args) {
            CloneInfo cloneInfo = new CloneInfo();
            cloneInfo.setUserName("Tom");
            cloneInfo.setPassWord("123");
    
            ArrayList<CloneInfo> list = new ArrayList<>();
            list.add(cloneInfo);
            ArrayList cloneList = (ArrayList)list.clone();
            System.out.println("修改实体数据前");
            System.out.println("原集合:"+list);
            System.out.println("克隆集合:"+cloneList);
            System.out.println("修改实体数据后");
            list.get(0).setUserName("Jack");
            System.out.println("原集合:"+list);
            System.out.println("克隆集合:"+cloneList);
    }

     

           而当我们以相同的操作去更改一个引用类型对象的时候,发现克隆集合的数据也在跟着变化,这就是浅拷贝:clone对象时,对于基本数据类型拷贝其值,引用数据类型拷贝其内存地址(String类型也遵循这个规律,只不过因为常量池的关系宏观表现上和基本数据类型一致)。深拷贝:clone对象时,基本数据类型拷贝其值,引用数据类型会重新生成一块内存地址,而不是再指向原有内存地址

    4.如何实现深拷贝

         4.1 手动为引用类型赋值

           思路:既然直接调用基类clone方法只能进行浅拷贝,但如果是引用类型的话还是可以调用clone方法继续进行浅拷贝,一直套娃下去终有一天会将所有的引用类型都拷贝成基本数据类型,然后再一层一层嵌套返回回来,就实现了深拷贝(哈哈哈,曲线救国)。如果需要拷贝的类中没有引用类型嵌套,那么就在重写clone方法时自己new一个对象出来,然后把所有属性手动set回去。

    Demo1:

    @Data
    public class CloneInfo implements Cloneable{
    
        private  CloneInfo2 cloneInfo2;
    
        @Override
        protected CloneInfo clone() throws CloneNotSupportedException {
            CloneInfo cloneInfo = (CloneInfo) super.clone();
            if(cloneInfo2 != null){
                cloneInfo.cloneInfo2 = (CloneInfo2)cloneInfo2.clone();
            }
            return cloneInfo;
        }
    }
    public static void main(String[] args) throws CloneNotSupportedException {
            CloneInfo info = new CloneInfo();
            info.setCloneInfo2(new CloneInfo2());
            CloneInfo cloneInfo = info.clone();
            System.out.println("对象内存地址:"+info.getCloneInfo2());
            System.out.println("对象内存地址:"+cloneInfo.getCloneInfo2());
    }

           可以看到CloneInfo内嵌的CloneInfo2对象内存地址已经发生改变,深拷贝成功。

    Demo2:

    public class CloneInfo implements Cloneable{
    
        private  String userName;
        private  String passWord;
    
        @Override
        protected CloneInfo clone() throws CloneNotSupportedException {
            CloneInfo cloneInfo = (CloneInfo) super.clone();
            CloneInfo returnCloneInfo = new CloneInfo();
            returnCloneInfo.setUserName(cloneInfo.getUserName());
            returnCloneInfo.setPassWord(cloneInfo.getPassWord());
            return returnCloneInfo;
        }
    
        public String getUserName() {
            return userName;
        }
        public void setUserName(String userName) {
            this.userName = userName;
        }
        public String getPassWord() {
            return passWord;
        }
        public void setPassWord(String passWord) {
            this.passWord = passWord;
        }
    }
    public static void main(String[] args) throws CloneNotSupportedException {
            CloneInfo info = new CloneInfo();
            info.setUserName("Tom");
            info.setPassWord("123");
            CloneInfo cloneInfo = info.clone();
            System.out.println("对象内存地址:"+info);
            System.out.println("对象内存地址:"+cloneInfo);
            System.out.println("修改实体数据前");
            System.out.println("原实体:"+info.getUserName());
            System.out.println("克隆实体:"+cloneInfo.getUserName());
            System.out.println("修改实体数据后");
            info.setUserName("Jack");
            System.out.println("原实体:"+info.getUserName());
            System.out.println("克隆实体:"+cloneInfo.getUserName());
    }

         4.2 使用对象流进行深拷贝

           思路:将对象写入流中再读出来实现深拷贝。

    public static void main(String[] args) throws Exception {
            CloneInfo info = new CloneInfo();
            info.setCloneInfo2(new CloneInfo2());
    
            ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
            ObjectOutputStream objOut = new ObjectOutputStream(byteOut);
            objOut.writeObject(info);
    
            ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());
            ObjectInputStream objInput = new ObjectInputStream(byteIn);
            CloneInfo cloneInfo= (CloneInfo) objInput.readObject();
            System.out.println("对象内存地址:"+info.getCloneInfo2());
            System.out.println("对象内存地址:"+cloneInfo.getCloneInfo2());
    }

    展开全文
  • 一、Cloneable接口 在实际编程过程中,我们常常要遇到这种情况:有一个对象A,在某一时刻A中已经包含了一些有效值,此时可能会需要一个和A完全相同的新对象B,并且此后对B任何改动都不会影响到A中的值。也就是说,A...

    一、Cloneable接口

    在实际编程过程中,我们常常要遇到这种情况:有一个对象A,在某一时刻A中已经包含了一些有效值,此时可能会需要一个和A完全相同的新对象B,并且此后对B任何改动都不会影响到A中的值。也就是说,A与B是两个独立的对象,但B的初始值是由A对象确定的。在Java语言中,用简单的赋值语句是不能满足这种需求的,需要使用clone。

    clone:它允许在堆中克隆出一块和原对象一样的对象,并将这个对象的地址赋予新的引用。简而言之,克隆就是快速构造一个和已有对象相同的副本。

    Java中的类要实现clone功能必须实现java.lang.Cloneable接口。Cloneable接口属于合法标志性接口(接口内不含有任何方法),只有实现这个接口后,然后在类中重写Object中的clone()方法,然后通过类的实例对象调用clone()方法才能克隆成功,否则就会抛出CloneNotSupportedException异常。

    Java中所有类都默认继承java.lang.Object类,在java.lang.Object类中有一个方法clone(),这个方法将返回Object对象的一个拷贝。要说明的有两点:一是拷贝对象返回的是一个新对象,而不是一个引用;二是拷贝对象与用 new操作符返回的新对象的区别就是这个拷贝已经包含了一些原来对象的信息,而不是对象的初始信息。

    如果一个类重写了 Object 内定义的 clone()方法 ,需要同时实现 Cloneable 接口(虽然这个接口内并没有定义 clone() 方法),否则会抛出异常,也就是说, Cloneable接口只是个合法调用 clone() 的标识(marker-interface)。

    class CloneClass implements Cloneable
    {
      public int aInt;
    
       //重写Object中的clone方法,并声明为public
      public Object clone()
      {
       CloneClass o = null;
       try
        {
         o = (CloneClass)super.clone();//调用父类Object的clone()方法
       }
         catch(CloneNotSupportedException e)
        {
          e.printStackTrace();
       }
       return o;
     }
    }

    1、有三个值得注意的地方:

    a>为了实现clone功能,CloneClass类实现了Cloneable接口,这个接口属于java.lang 包,java.lang包已经被缺省的导入类中,所以不需要写成java.lang.Cloneable;

    b>重写java.lang.Object.clone()方法,Object类中的clone()方法是一个protected属性的方法。这也意味着如果要应用clone()方法,必须继承Object类,在 Java中所有的类是缺省继承Object类的,也就不用关心这点了。

    这里有一个疑问,Object中的clone方法是一个空的方法,那么他是如何判断类是否实现了cloneable接口呢?

    原因在于这个方法中有一个native关键字修饰。native修饰的方法都是空的方法,但是这些方法都是有实现体的(这里也就间接说明了native关键字不能与abstract同时使用。因为abstract修饰的方法与java的接口中的方法类似,他显式的说明了修饰的方法,在当前是没有实现体的,abstract的方法的实现体都由子类重写),只不过native方法调用的实现体,都是非java代码编写的(调用的是在jvm中编写的C的接口),每一个native方法在jvm中都有一个同名的实现体,native方法在逻辑上的判断都是由实现体实现的,另外这种native修饰的方法对返回类型,异常控制等都没有约束。

     由此可见,这里判断是否实现cloneable接口,是在调用jvm中的实现体时进行判断的。

    总结:Object类的clone()方法是一个native方法,native方法的效率一般来说都是远高于java中的非native方法。这也解释了为 什么要用Object中clone()方法而不是先new一个对象,然后把原始对象中的信息赋到新对象中,虽然这也实现了clone功能,但因为这个实例的创建过程十分复杂,在执行过程中会消耗大量的时间,所以导致效率较低。

    c>为了让其它类能调用这个clone 类的clone()方法,重载之后要把clone()方法的属性设置为public。

    2、深入理解深度克隆与浅度克隆

    首先,在Java中创建对象的方式有四种:

            一种是new,通过new关键字在堆中为对象开辟空间,在执行new时,首先会看所要创建的对象的类型,知道了类型,才能知道需 要给这个对象分配多大的内存区域,分配内存后,调用对象的构造函数,填充对象中各个变量的值,将对象初始化,然后通过构造方法返回对象的地址;

          另一种是clone,clone也是首先分配内存,这里分配的内存与调用clone方法对象的内存相同,然后将源对象中各个变量的值,填充到新的对象中,填充完成后,clone方法返回一个新的地址,这个新地址的对象与源对象相同,只是地址不同。

    另外还有输入输出流,反射构造对象等

    深度克隆和浅度克隆,这东西虽然平常不怎么用,但是了解一下还是有必要的。Object中的克隆方法是浅度克隆,JDK规定了克隆需要满足的一些条件,简要总结一下就是:对某个对象进行克隆,对象的的成员变量如果包括引用类型或者数组,那么克隆的时候其实是不会把这些对象也带着复制到克隆出来的对象里面的,只是复制一个引用,这个引用指向被克隆对象的成员对象,但是基本数据类型是会跟着被带到克隆对象里面去的。而深度可能就是把对象的所有属性都统统复制一份新的到目标对象里面去。

    如下图所示:

     

    Java实现深度克隆的简单方法使用Java的流,先将对象序列化,然后序列化回对象,其中的限制为克隆的对象必须实现Serializable接口.。

    Java实现深度克隆的简单方法


    二、Serializable接口

    Serializable接口中一个成员函数或者成员变量也没有,这个接口的作用就是实现序列化,那什么是序列化?

    1、序列化

    Java提供了一种保存对象状态的机制,那就是序列化。

    对象的寿命通常随着生成该对象的程序的终止而终止,而有时候需要把在内存中的各种对象的状态(也就是实例变量,不是方法)保存下来,并且可以在需要时再将对象恢复。

    Java 序列化技术可以将一个对象的状态写入一个Byte 流里(序列化),并且可以从其它地方把该Byte 流里的数据读出来(反序列化)。

    2、什么时候需要序列化

    想把内存中的对象状态保存到一个文件中或者数据库中时候;
    想把对象通过网络进行传播的时候。

    3、如何序列化

    只要一个类实现Serializable接口,那么这个类就可以序列化了。

    举个栗子:

    class Person implements Serializable
    {   
        //一会就说这个是做什么的
        private static final long serialVersionUID = 1L; 
    
        String name;
        int age;
        public Person(String name,int age){
            this.name = name;
            this.age = age;
        }   
        public String toString(){
            return "name:"+name+"\tage:"+age;
        }
    }

    通过ObjectOutputStream 的writeObject()方法把这个类的对象写到一个地方(文件),再通过ObjectInputStream 的readObject()方法把这个对象读出来。

    File file = new File("file"+File.separator+"out.txt");
    
        /*
         * 1、序列化
         */
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(file);
            ObjectOutputStream oos = null;
            try {
                oos = new ObjectOutputStream(fos);
                Person person = new Person("tom", 22);
                // 调用 person的 tostring() 方法
                System.out.println(person);
                //写入对象
                oos.writeObject(person);            
                oos.flush();
            } catch (IOException e) {
                e.printStackTrace();
            }finally{
                try {
                    oos.close();
                } catch (IOException e) {
                    System.out.println("oos关闭失败:"+e.getMessage());
                }
            }
        } catch (FileNotFoundException e) {
            System.out.println("找不到文件:"+e.getMessage());
        } finally{
            try {
                fos.close();
            } catch (IOException e) {
                System.out.println("fos关闭失败:"+e.getMessage());
            }
        }
    
       /*
         *2、反序列化
         */
        FileInputStream fis = null;
        try {
            fis = new FileInputStream(file);
            ObjectInputStream ois = null;
            try {
                ois = new ObjectInputStream(fis);
                try {
                    Person person = (Person)ois.readObject();   //读出对象
                    System.out.println(person);
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                } 
            } catch (IOException e) {
                e.printStackTrace();
            }finally{
                try {
                    ois.close();
                } catch (IOException e) {
                    System.out.println("ois关闭失败:"+e.getMessage());
                }
            }
        } catch (FileNotFoundException e) {
            System.out.println("找不到文件:"+e.getMessage());
        } finally{
            try {
                fis.close();
            } catch (IOException e) {
                System.out.println("fis关闭失败:"+e.getMessage());
            }
        }

    运行结果:

    name:tom    age:22
    name:tom    age:22

    结果完全一样;如果把Person类中的implements Serializable 去掉,Person类就不能序列化了,此时再运行上述程序,就会报java.io.NotSerializableException异常。

    4、serialVersionUID

    注意到上面程序中有一个 serialVersionUID ,实现了Serializable接口之后,Eclipse就会提示你增加一个 serialVersionUID,虽然不加的话上述程序依然能够正常运行。

    序列化 ID 在 Eclipse 下提供了两种生成策略

    一个是固定的 1L
    一个是随机生成一个不重复的 long 类型数据(实际上是使用 JDK 工具,根据类名、接口名、成员方法及属性等来生成)
    上面程序中,输出对象和读入对象使用的是同一个Person类。

    如果是通过网络传输的话,如果Person类的serialVersionUID不一致,那么反序列化就不能正常进行。例如在客户端A中Person类的serialVersionUID=1L,而在客户端B中Person类的serialVersionUID=2L, 那么就不能重构这个Person对象。

    试图重构就会报java.io.InvalidClassException异常,因为这两个类的版本不一致,local class incompatible,重构就会出现错误。如果没有特殊需求的话,使用用默认的 1L 就可以,这样可以确保代码一致时反序列化成功。那么随机生成的序列化 ID 有什么作用呢,有些时候,通过改变序列化 ID 可以用来限制某些用户的使用。

    5、transient关键字

    经常在实现了 Serializable接口的类中能看见transient关键字。 transient关键字的作用是:阻止实例中那些用此关键字声明的变量持久化;当对象被反序列化时(从源文件读取字节序列进行重构),这样的实例变量值不会被持久化和恢复。

    当某些变量不想被序列化,同是又不适合使用static关键字声明,那么此时就需要用transient关键字来声明该变量。

    例如用 transient关键字 修饰name变量

    class Person implements Serializable{   
    
        private static final long serialVersionUID = 1L;
    
        transient String name;
        int age;
    
        public Person(String name,int age){
            this.name = name;
            this.age = age;
        }   
        public String toString(){
            return "name:"+name+"\tage:"+age;
        }
    }

    在反序列化视图重构对象的时候,作用与static变量一样, 输出结果为:

    name:null   age:22

    在被反序列化后,transient 变量的值被设为初始值,如 int 型的是 0,对象型的是 null。

    注:对于某些类型的属性,其状态是瞬时的,这样的属性是无法保存其状态的。例如一个线程属性或需要访问IO、本地资源、网络资源等的属性,对于这些字段,我们必须用transient关键字标明,否则编译器将报措。

    展开全文
  • Java中Cloneable的使用

    2020-03-20 10:37:19
    Java中Cloneable的使用 1. Cloneable的用途 Cloneable是标记型的接口,它们内部都没有方法和属性,实现 Cloneable来表示该对象能被克隆,能使用Object.clone()方法。如果没有实现 Cloneable的类对象调用clone()就...

    Java中Cloneable的使用

    1. Cloneable的用途

    Cloneable是标记型的接口,它们内部都没有方法和属性,实现 Cloneable来表示该对象能被克隆,能使用Object.clone()方法。如果没有实现 Cloneable的类对象调用clone()就会抛出CloneNotSupportedException。

    2. 克隆的分类

    • 浅克隆(shallow clone),浅克隆是指拷贝对象时仅仅copy对象本身对象中的基本变量,而不拷贝对象包含的引用指向的对象。

    • 深克隆(deep clone),不仅copy对象本身,而且copy对象包含的引用指向的所有对象。

      举例:对象X中包含对Y的引用,Y中包含对Z的引用。浅拷贝X得到X1,X1中依然包含对Y的引用,Y中依然包含对Z的引用。深拷贝则是对浅拷贝的递归,深拷贝X得到X1,X1中包含对Y1(Y的copy)的引用,Y1中包含对Z1(Z的copy)的引用。

    3. 克隆代码举例

    要让对象可以被克隆,应具备以下2个条件:

    • 让该类实现java.lang.Cloneable接口;

    • 重写(Override)Object的clone()方法;

    
    package com.lgl;
    
    public class Info implements Cloneable {
    
        private int id;
    
        private String text;
    
    
    
        public Info(int id, String text) {
    
            this.id = id;
    
            this.text = text;
    
        }
    
    
    
        @Override
    
        public boolean equals(Object obj) {
    
            if (this == obj) {
    
                return true;
    
            }
    
            if (obj == null) {
    
                return false;
    
            }
    
            if (obj.getClass()!= getClass()) {
    
                return false;
    
            }
    
            Info temp = (Info) obj;
    
            if (id != temp.id) {
    
                return false;
    
            }
    
            if (text == null) {
    
                if (temp.text != null) {
    
                    return false;
    
                }
    
            } else if (!text.equals(temp.text)) {
    
                return false;
    
            }
    
            return true;
    
        }
    
    
    
        @Override
    
        protected Object clone() throws CloneNotSupportedException {
    
            return super.clone();
    
        }
    
    
    
        public static void main(String[] args) throws CloneNotSupportedException {
    
            Info info1 = new Info(1, "I am Colyn Lu.");
    
            Info info2 = (Info) info1.clone();
    
    
    
            System.out.println(info1.getClass() == info2.getClass());//true
    
            System.out.println(info1 == info2);//false
    
            System.out.println(info1.equals(info2));//true
    
        }
    
    }
    
    

    4. 浅克隆

    
    package com.lgl;
    
    public class MyFile implements Cloneable {
    
        private String path;
    
        private Info info;
    
    
    
        public MyFile(String path, Info info) {
    
            this.path = path;
    
            this.info = info;
    
        }
    
    
    
        @Override
    
        public boolean equals(Object obj) {
    
            if (this == obj) {
    
                return true;
    
            }
    
            if (obj == null) {
    
                return false;
    
            }
    
            if (obj.getClass()!= getClass()) {
    
                return false;
    
            }
    
            MyFile temp = (MyFile) obj;
    
            if (path == null) {
    
                if (temp.path != null) {
    
                    return false;
    
                }
    
            } else if (!path.equals(temp.path)) {
    
                return false;
    
            }
    
            if (info == null) {
    
                if (temp.info != null) {
    
                    return false;
    
                }
    
            } else if (!info.equals(temp.info)) {
    
                return false;
    
            }
    
            return true;
    
        }
    
    
    
        @Override
    
        protected Object clone() throws CloneNotSupportedException {
    
            return super.clone();
    
        }
    
    
    
        public static void main(String[] args) throws CloneNotSupportedException {
    
            Info info = new Info(2, "Hello world.");
    
            MyFile file1 = new MyFile("c:", info);
    
            MyFile file2 = (MyFile) file1.clone();
    
    
    
            System.out.println(file1.getClass() == file2.getClass());//true
    
            System.out.println(file1 == file2);//false
    
            System.out.println(file1.equals(file2));//true
    
            System.out.println(file1.info.getClass() == file2.info.getClass());//true
    
            System.out.println(file1.info == file2.info);//true
    
            System.out.println(file1.info.equals(file2.info));//true
    
        }
    
    }
    
    

    5.深克隆

    深克隆需要重写(Override)Object类的clone()方法,并且在方法内部调用持有对象的clone方法。

    
    package com.lgl;
    
    public class MyFile2 implements Cloneable {
    
        private String path;
    
        private Info info;
    
    
    
        public MyFile2(String path, Info info) {
    
            this.path = path;
    
            this.info = info;
    
        }
    
    
    
        @Override
    
        public boolean equals(Object obj) {
    
            if (this == obj) {
    
                return true;
    
            }
    
            if (obj == null) {
    
                return false;
    
            }
    
            if (obj.getClass()!= getClass()) {
    
                return false;
    
            }
    
            MyFile2 temp = (MyFile2) obj;
    
            if (path == null) {
    
                if (temp.path != null) {
    
                    return false;
    
                }
    
            } else if (!path.equals(temp.path)) {
    
                return false;
    
            }
    
            if (info == null) {
    
                if (temp.info != null) {
    
                    return false;
    
                }
    
            } else if (!info.equals(temp.info)) {
    
                return false;
    
            }
    
            return true;
    
        }
    
    
    
        @Override
    
        protected Object clone() throws CloneNotSupportedException {
    
            MyFile2 file = (MyFile2) super.clone();
    
            file.info = (Info) file.info.clone();
    
    
    
            return file;
    
        }
    
    
    
        public static void main(String[] args) throws CloneNotSupportedException {
    
            Info info = new Info(2, "Hello world.");
    
            MyFile2 file1 = new MyFile2("c:", info);
    
            MyFile2 file2 = (MyFile2) file1.clone();
    
    
    
            System.out.println(file1.getClass() == file2.getClass());//true
    
            System.out.println(file1 == file2);//false
    
            System.out.println(file1.equals(file2));//true
    
            System.out.println(file1.info.getClass() == file2.info.getClass());//true
    
            System.out.println(file1.info == file2.info);//false
    
            System.out.println(file1.info.equals(file2.info));//true
    
        }
    
    }
    
    展开全文
  • java-Cloneable接口

    千次阅读 2018-07-02 17:31:30
    一个类实现了Cloneable接口 指向@link java.lang.Object#clone()} 方法是合法的 使得一个 field-for-field copy的类的实例的拷贝 在不实现Cloneable接口的对象上调用Object的clone方法 会导致...
  • Cloneable接口

    2021-04-21 13:43:47
    Cloneable接口 1、Cloneable接口 Cloneable是一个接口,实现这个接口后,可以在类中重写Object中的clone方法,然后通过类调用clone方法进行克隆,如果不实现Cloneable接口,则会抛出CloneNotSupportedException异常...
  • Cloneable接口的作用与深入理解深度克隆与浅度克隆

    万次阅读 多人点赞 2018-07-23 21:54:22
    cloneable接口的作用 cloneable其实就是一个标记接口,只有实现这个接口后,然后在类中重写Object中的clone方法,然后通过类调用clone方法才能克隆成功,如果不实现这个接口,则会抛出CloneNotSupportedException...
  • 要让实例调用clone方法就需要让此类实现Cloneable接口,API里面还有句话是:如果在没有实现 Cloneable 接口的实例上调用 Object 的 clone 方法,则会导致抛出 CloneNotSupportedException 异常,这便是“合法”的...
  • Cloneable接口与Serializable接口都是定义接口而没有任何的方法。Cloneable可以实现对象的克隆复制,Serializable主要是对象序列化的接口定义。很多时候我们涉及到对象的复制,我们不可能都去使用setter去实现,这样...
  • Cloneable实现对象克隆

    2019-06-04 13:46:25
    本篇文章主要是对Cloneable接口如何实现对象克隆展开。 首先需要声明下,对象有分为浅克隆和深克隆。 浅克隆 浅克隆是对要克隆的对象,其中的基本类型复制一份新的产生给对象。但是对于非基本类型的数据类型,...
  • 来自包管理器控制台或 .NET Core CLI 的任一命令都将下载并安装 Cloneable 和所有必需的依赖项。 用法 您可以通过使其成为部分类并在其顶部添加属性Cloneable来向类添加克隆方法。 Cloneable.Sample 项目中提供了一...
  • 使用cloneable接口实现原型模式,包括浅复制、深复制 ******************************************** 相关接口 Cloneable public interface Cloneable { } 说明:该接口只是一个标识接口,表明类可被复制...
  • 实现 implements Cloneable接口,因为Object没有实现Cloneable接口 package com.hou.pojo; //object类本身并没有实现Cloneable这个接口,所以需要我们自己进行实现 public class User extends Object implements ...
  • 转自:https://blog.csdn.net/xiaomingdetianxia/article/details/74453033Cloneable接口clone:它...Java 中 一个类要实现clone功能 必须实现 Cloneable接口,否则在调用 clone() 时会报 CloneNotSupportedExcep...
  • deep_cloneable 这个gem为每个ActiveRecord :: Base对象提供了进行深度克隆的可能性,该克隆包括用户指定的关联。 这是的Rails 3+升级。 要求 Ruby 1.9.3、2.0.0、2.1.5、2.2.2、2.3.0、2.4.4、2.5.5、2.6.3(已...
  • 一、Cloneable接口 Cloneable只是一个标记接口,只有实现了这个接口,才能在类中重写clone方法,然后通过类调用clone完成功能实现,如果不实现这个接口,则会抛出CloneNotSupportedException(克隆不被支持)异常 1、...
  • 小结 1:深克隆,在不引入...实现Cloneable接口其实并不是安全的深克隆方式,如果被克隆对象含有引用类型,如果在重写 public Object clone()的时候,不对这个引用对象也进行克隆的话,这个引用对象是不安全的,会被...
  • Cloneable的用法

    2019-08-12 17:07:45
    Cloneable的用法 1、如果需要对象能被克隆,则该类要继承Cloneable接口。 2、在类里重写Object的clone方法。 3、clone方法默认实现的是浅复制,也就是只是给新对象复制了源对象的引用,并不是复制值。 4、所以需要...
  • Cloneable接口的作用与深克隆、浅克隆的理解 文章目录Cloneable接口的作用与深克隆、浅克隆的理解一、简介1. 为什么需要克隆2. Cloneable接口的作用3. 如何实现克隆二、浅克隆和深克隆介绍三、代码演示1. 浅克隆2. ...
  • 2)是否可以在可变的子对象上调用clone()方法来修补默认的clone()方法 如果满足以上任意一项,类必须: 1)实现Cloneable接口 2)重新定义clone方法,并指定pulic访问修饰符 4.实例 import java.util.Date; ​ ...
  • 不然无法序列化,报错 此块和Cloneable接口的不一样,(实现cloneable接口的此类,下面的类对象类,可以/可以不 实现cloneable接口) 4、遇自定义类皆实现Cloneable接口的深拷贝(前面2、说的是浅拷贝) 3、代码实现...
  • 实现 Cloneable接口深度克隆对象 Body对象中有Head对象,Head对象中有Face对象,Face对象中有int变量和String变量。 实现Boby对象的深度克隆,看下面代码: package com.example.dumengen; import org.slf4j.Logger...
  • 1. Cloneable接口的作用 Cloneable是标记型的接口,它们内部都没有方法和属性,实现 Cloneable来表示该对象能被克隆,能使用Object.clone()方法。如果没有实现 Cloneable的类对象调用clone()就会抛出...
  • kotlin Cloneable 的奇怪行为 在使用 kotlin 的 Cloneable 时,发现它表示得很奇怪。如果类直接继承了 Cloneable ,那么它的表现很正常 和 java 的使用差不多,如下: package demo interface Foo { fun ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 71,178
精华内容 28,471
关键字:

cloneable