精华内容
下载资源
问答
  • 目录Clonable接口Clonable接口结合深拷贝问题与浅拷贝问题 Clonable接口 在抽象类和接口的博客中,我们讲到了两个我们会常用到的接口,一个是Compareable接口,一个是Comperator接口,现在我们再来讲一个我们会经常...

    Clonable接口

    在抽象类和接口的博客中,我们讲到了两个我们会常用到的接口,一个是Compareable接口,一个是Comperator接口,现在我们再来讲一个我们会经常用到的接口,也就是我们的Clonable接口.

    首先我们来思考一个问题:如何进行对象的拷贝?
    Object 类中存在一个 clone 方法, 调用这个方法可以创建一个对象的 "拷贝". 但是要想合法调用 clone 方法, 必须要先实现 Clonable 接口, 否则就会抛出 CloneNotSupportedException 异常.
    我们先来看Clonable接口的源码:
    在这里插入图片描述

    我们可以看到这类接口什么都没有,那么我们称这类接口为空接口,也就是标记接口.
    空接口的意义:标记当前这个类可以被克隆的.克隆会做一件事情,拷贝一份副本.

    同时关于对象的拷贝会牵扯出之前我们所提到的深拷贝和浅拷贝的问题,下面我们来进行对比:

    Clonable接口结合深拷贝问题与浅拷贝问题

    首先一个对象的引用如果想要进行克隆,那么其对应的类必须实现Clonable 接口,并且重写Object类中的clone方法,并且重写的clone方法后必须抛出CloneNotSupportedException 异常.

    Clonable接口结合深拷贝

    我们直接通过代码来进行解析:先来看一段代码:

    1.class Person implements Cloneable {  
    2.    public int age;  
    3.    @Override  
    4.   //此处的clone方法必须抛出CloneNotSupportedException异常  
    5.    protected Object clone() throws CloneNotSupportedException {  
    6.        return super.clone();  
    7.    }  
    8.}  
    9.//此处的主函数也需要抛出这个异常
    10. public static void main(String[] args) throws CloneNotSupportedException {  
    11.        Person person = new Person();  
    12.        /*注意对于下面的调用clone方法有两点需要注意: 
    13.        1:首先引用在调用clone方法时main方法需要抛出CloneNotSupportedException异常 
    14.        2:因为clone方法的返回值为引用类型Object,所以如果是其他类定义的引用就需要强制类型转换 
    15.         */  
    16.        Person person1 = (Person) person.clone();  
    17.        System.out.println(person.age);  
    18.        System.out.println(person1.age);  
    19.        System.out.println("===========对比===========");  
    20.        person1.age = 10;  
    21.        System.out.println(person.age);  
    22.        System.out.println(person1.age);  
    23.    }  
    

    此段代码的输出结果为:
    在这里插入图片描述
    此时我们会发现首先我们对person所指向的对象进行了拷贝,并把它赋给了一个新的引用person1,那么此时在内存是什么样的呢?我们来看下图所示:
    在这里插入图片描述
    此时我们可以看到通过clone方法我们在堆上克隆了一个副本,并将这个副本对象赋给了一个新的引用,并且当我们修改person1这个引用所指向对象中所包含的简单类型age的值时,person这个引用所指向对象中所包含i的简单类型age的值并没有发生改变,那么这种情况我们便称之为深拷贝即当拷贝结束后,通过一个新的引用修改所拷贝的新的对象的其中的某个类型的值时,并不影响原来引用所对应的相同对象中的相同类型的值,那么此时便为深拷贝

    Clonable接口结合浅拷贝

    下面我们来介绍浅拷贝:
    因为之前堆上的对象内部存储都是简单类型,所以都是深拷贝,那么如果存储引用类型后,就会发生浅拷贝了,下面来看代码:

    1.class Money {  
    2.    double money = 12.6;  
    3.}  
    4.  
    5.class Person implements Cloneable {  
    6.    public int age;  
    7.    Money m = new Money();  
    8.  
    9.    @Override  
    10.    //此处的clone方法必须抛出CloneNotSupportedException异常  
    11.    protected Object clone() throws CloneNotSupportedException {  
    12.        return super.clone();  
    13.    }  
    14.}  
    15.  
    16.public class TestDemo {  
    17.    public static void main(String[] args) throws CloneNotSupportedException {  
    18.        Person person = new Person();  
    19.        Person person1 = (Person) person.clone();  
    20.        System.out.println(person.m.money);  
    21.        System.out.println(person1.m.money);  
    22.        System.out.println("===========对比===========");  
    23.        person1.m.money = 99.9;  
    24.        System.out.println(“修改后为”+person.m.money);  
    25.        System.out.println(“修改后为”+person1.m.money);  
    26.    }  
    27.}  
    

    此时我们新建了一个Money类,并在Person类中加入了Money类的实例,那么此时Person类的实例在堆上的存储中便会多出一个引用类型,那么来看下其在内存上的存储示意图吧:
    在这里插入图片描述
    此时我们会发现我们通过clone方法仅仅将简单类型age和引用类型m克隆了过来但是m所指向的对象我们并没有克隆过来,那么两者的m引用都将会指向同一个对象
    此时如果我们通过person1.m.money去修改money的值为99.9时我们会发现原引用person所对应的money值也随之变成了99.9,那么这种现象我们称之为浅拷贝即其当一个新的引用去修改其克隆过来的对象中的某个类型(此段代码为引用类型)的值后,原引用调用这个类型时便会发现这个值为新修改后的值了,并不是原来的值
    所以上述代码中的最终结果我们会发现当其中一个引用修改了值后,另一个引用去调用时也会得到相同的值,我们来看运行结果以证实我们的猜想吧
    在这里插入图片描述
    果然就算修改过后两者的值依然相等

    将深拷贝改为浅拷贝的方法

    此时就会有同学有疑问了,上述代码如何可以实现深拷贝呢?
    答案非常简单:此时我们让Money类实现Cloneable接口就好。目的就是为了将Money类的实例也能通过clone方法拷贝过来,下面来看代码:

    1.class Money  implements Cloneable {  
    2.    double money = 12.6;  
    3.  
    4.    @Override  
    5.    protected Object clone() throws CloneNotSupportedException {  
    6.        return super.clone();  
    7.    }  
    8.}  
    9.  
    10.class Person implements Cloneable {  
    11.    public int age;  
    12.     Money m = new Money();  
    13.  
    14.    //重写Object类中的clone方法 ,并且必须抛出CloneNotSupportedException异常
    15.    @Override  
    16.    protected Object clone() throws CloneNotSupportedException {  
    17.        //克隆person所指向的对象  
    18.        Person p = (Person) super.clone();  
    19.        //克隆Person类中的另一个引用类型m所指向的对象  
    20.        p.m = (Money) this.m.clone();  
    21.        return p;  
    22.    }  
    23.}  
    24.  
    25.public class TestDemo {  
    26.    public static void main(String[] args) throws CloneNotSupportedException {  
    27.        Person person = new Person();  
    28.        Person person1 = (Person) person.clone();  
    29.        System.out.println(person.m.money);  
    30.        System.out.println(person1.m.money);  
    31.        System.out.println("===========对比===========");  
    32.        person1.m.money = 99.9;  
    33.        System.out.println("修改后的结果为"+person.m.money);  
    34.        System.out.println("修改后的结果为"+person1.m.money);  
    35.    }  
    36.}  
    

    内存示意图:
    在这里插入图片描述
    最终的输出结果为:
    在这里插入图片描述
    此时我们发现当通过语句person1.m.money修改money值后,并不影响person引用所指向对象中的m引用所指向对象中的money值,那么此时便发生了深拷贝,我们的目的达到了。

    展开全文
  • Comparable,Comparator,Clonable 接口使用剖析

    多人点赞 热门讨论 2021-10-23 21:20:59
    接口可以由类通过emplements关键字实现,一个类实现了某一个接口,就具备了该接口的一些功能,就可以完成一些操作。 Comparable接口 排序基本数据类型,如int ,long 等,我们可以使用 Arrays.sort()方法进行排序,...

    前言

    java中有许多的接口,今天我向大家简单的介绍我们平时常见的三个接口及其用法。接口可以由类通过emplements关键字实现,一个类实现了某一个接口,就具备了该接口的一些功能,就可以完成一些操作。

    Comparable接口

    排序基本数据类型,如int ,long 等,我们可以使用 Arrays.sort()与Collections.sort(),并且这个排序默认为升序排序是无法改变的,如下面的排序整形数组:

      public static void main(String[] args) {
            int[] array = {19,3,2,18,7,4};
            System.out.println(Arrays.toString(array));
            Arrays.sort(array);
            System.out.println(Arrays.toString(array));
        }
    

    那我们有时候要排列自定义数据类型,不管我们想按升序排列还是降序排列都可以那要如何操作呢????
    在下面的代码中,我定义了一个学生类,如果我们也用 Arrays.sort()方法对学生对象进行排序就会出错,这是因为我们在比较对象的时候没有指定比较规则,比较学生时到底是按姓名排序,还是年龄,还是分数,编译器不知道就会报如下的错误了:
    在这里插入图片描述

    class Student  {
        private String name;
        private int age;
        private double score;
    
        public Student(String name, int age, double score) {
            this.name = name;
            this.age = age;
            this.score = score;
        }
        @Override
        public String toString() {
            return "Student{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    ", score=" + score +
                    '}';
        }
    }
    
    public class TestDemo {
        public static void main(String[] args) {
            Student[] students = new Student[3];
            students[0] = new Student("gb",28,99.9);
            students[1] = new Student("bit",18,19.9);
            students[2] = new Student("ang",98,69.9);
            System.out.println("排序前:"+Arrays.toString(students));
            Arrays.sort(students);
            System.out.println("排序后:"+Arrays.toString(students));
        }
    
    

    那么划红线的Comparable是什么呢?其实它是一个接口,里面有比较函数compare,我们只要student实现这个接口,就具备了比较的能力,之后重写一下比较规则,你到底是要按姓名排序,还是分数,还是年龄排序不就行了。

    class Student implements Comparable<Student> {//<Student>是泛型的知识,之后讲解,Student表示我们要比较是什么类型的数据
        private String name;
        private int age;
        private double score;
    
        public Student(String name, int age, double score) {
            this.name = name;
            this.age = age;
            this.score = score;
        }
    
        @Override
        public String toString() {
            return "Student{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    ", score=" + score +
                    '}';
        }
    
        //比较规则
        @Override
        public int compareTo(Student o) {
            return (int) (this.score - o.score);//分数升序排列
            //return (int) (o.score - this.score);//分数降序排列
            //return this.name.compareTo(o.name);//以姓名进行比较
            //return o.age-this.age;//年龄降序排列
            //=============================================
            //上面代码的分解
            /*if(this.age > o.age) {
                return 1;
            }else if(this.age == o.age) {
                return 0;
            }else {
                return -1;
            }*//*
        }
    }*/
     }
    
    }
    

    那如何自定义升序降序排列呢???有什么规律呢,首先我们来来看一下Arrays.sort这个函数的部分源码。
    在这里插入图片描述

      for (int i=low; i<high; i++)
                    for (int j=i; j>low &&
                             ((Comparable) dest[j-1]).compareTo(dest[j])>0; j--)
                        swap(dest, j, j-1);
                return;
            }
    

    由源码我们可以大概的知道,对于要排序的数组元素,是前一个元素和后一个元素进行比较时调用compareTo方法,而compareTo方法是我们重写的比较规则,比较规则中我们会返回大于0,等于0,小于0的数字,如果返回大于0的数字,则交换两个元素的位置再由上面的compareTo方法和源码可知,o指向的对象是要比较的两个元素的后面的那一个元素,this指向的元素是要比较的两个元素中前面的一个元素,比较时如果写成(this.score - o.score)也就是说前一个元素大于后一个元素返回大于0的数字,才交换,这样就是升序排列了,相反就是降序排列。
    那么我们再来想想Comparable接口有什么不好的地方??从代码可以发现它对类的侵入性比较强,也就是说每次如果更换了比较方式,那么都需要修改类的内部局限性很大,很麻烦,那么有对于比较有更好的,更便捷的比较接口吗?那就是我们接下来,要讲的接口了。

    Comparator接口

    Comparator接口实际上就是对Comparable的升级完善,有了它可以使我们在比较一些自定义数据的时候更加方便,快捷。例如对于我们上面自定义的学生类的实例,我们可以按年龄,分数,姓名实现我们想要的排序。只要我们实现各种比较器,在排序的时候传一个比较器给 Arrays.sort()即可,这样对类的侵入性就比较弱,不需要频繁地改变类的内部,比较器其实就是比较规则,我们实现一个类实现Comparator接口之后重写接口里面的抽象方法就行了。

    class Student {
        private String name;
        private int age;
        private double score;
    
        public Student(String name, int age, double score) {
            this.name = name;
            this.age = age;
            this.score = score;
        }
    
        @Override
        public String toString() {
            return "Student{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    ", score=" + score +
                    '}';
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        public double getScore() {
            return score;
        }
    
        public void setScore(double score) {
            this.score = score;
        }
    }
    //比较器
    class AgeComparator implements Comparator<Student> {
    
        @Override
        public int compare(Student o1, Student o2) {
            return o1.getAge()-o2.getAge();
        }
    }
    class NameComparator implements Comparator<Student> {
        @Override
        public int compare(Student o1, Student o2) {
            return o1.getName().compareTo(o2.getName());
        }
    }
    class ScoreComparator implements Comparator<Student> {
        @Override
        public int compare(Student o1, Student o2) {
            return (int)(o1.getScore()-o2.getScore());
        }
    }
    
    
     public static void main(String[] args) {
            Student[] students = new Student[3];
            students[0] = new Student("gb",28,99.9);
            students[1] = new Student("bit",18,19.9);
            students[2] = new Student("ang",98,69.9);
            System.out.println("排序前:"+Arrays.toString(students));
            AgeComparator ageComparator = new AgeComparator();
            NameComparator nameComparator = new NameComparator();
            ScoreComparator scoreComparator = new ScoreComparator();
            Arrays.sort(students,scoreComparator);
            System.out.println("排序后:"+Arrays.toString(students));
        }
    
    

    上面在比较名字的时候也是要用compareTo()方法,名字是字符串源码底层说的比较抽象,大体总结白话说出来,String 是字符串,它的比较用compareTo方法,首先比较两个字符串的长度,当长度不同时返回的是字符串的长度差,长度相同时,它从第一位开始往后比较, 如果遇到不同的字符,则马上返回这两个字符的ASCII值差值.返回值是int类型。

    Comparable,Comparator两者简单比较:
    Comparable 是排序接口;若一个类实现了 Comparable 接口,就意味着 “该类支持排序”。而 Comparator 是比较器;我们若需要控制某个类的次序,可以建立一个 “该类的比较器” 来进行排序。前者应该比较固定,对类的侵入性也比较强,它和一个具体类相绑定,而后者比较灵活,对类的侵入性也比较弱,它可以被用于各个需要比较功能的类使用。

    Clonable 接口和深拷贝

    Object 类中存在一个 clone方法, 调用这个方法可以创建一个对象的 “拷贝”. 但是要想合法调用 clone 方法, 必须要先实现 Clonable 接口, 否则就会抛出 CloneNotSupportedException 异常.

    class Person implements Cloneable{
        public String name;
        @Override
        public String toString() {
            return "Person{" +
                    "name='" + name + '\'' +
                    '}';
        }
    
        public Person(String name) {
            this.name = name;
        }
        //Object类的克隆方法。所有的类  默认继承与Object类
        @Override
        protected Object clone() throws CloneNotSupportedException {
            //return super.clone();
            return  super.clone();
        }
    }
    public class TestDemo1 {
        public static void main(String[] args) throws CloneNotSupportedException {
            Person person=new Person("lmm");
            System.out.println(person);
            Person person2 = (Person)person.clone();//注意强制类型转换
            System.out.println(person2);
        }
    }
    

    实现了这个接口还没有完事,还要重写这个接口里面的方法clone(),因为由源码可知,这个接口里面没有任何方法,之后还要注意类型转换,方法的返回值类型是Object ,下面调用的时候,我们要把它转换为克隆对象的类型之后就可以打印出来我们克隆的对象了。
    在这里插入图片描述
    接着讲接口,我们来说一下有关Clonable接口实现深浅拷贝的问题。如下面的代码我克隆出了一个对象person2,通过这个对象去访问里面的成员变量,并且改动了它,原来父本里面的内容是不会被改变的,像这样的拷贝就是一个深拷贝

    class Person implements Cloneable {
        public String name;
        // public Money money = new Money();
        public int a = 10;
    
        public Person(String name) {
            this.name = name;
        }
    
        @Override
        public String toString() {
            return "Person{" +
                    "name='" + name + '\'' +
                    '}';
        }
        //Object类的克隆方法。所有的类  默认继承与Object类
    
        @Override
        protected Object clone() throws CloneNotSupportedException {
            //return super.clone();
            return super.clone();
            /*Person personClone = (Person) super.clone();
            personClone.money = (Money)this.money.clone();
            return personClone;*/
        }
    
    }
    
    public  class TestDemo1 {
        public static void main(String[] args) throws CloneNotSupportedException {
            Person person = new Person("lmm");
            Person person2 = (Person)person.clone();
    
            System.out.println(person.a);//10
            System.out.println(person2.a);//10
            System.out.println("=========================");
            person2.a = 99;
            System.out.println(person.a);//10
            System.out.println(person2.a);//99
        }
    }
    
    

    如像下面的代码实现就是一个浅拷贝了,下面的代码只是Person成员变量多了一个Money类的实例,Money类里面有成员变量money = 12.5;之后克隆出了一个对象person2,通过这个对象去访问里面的成员变量,并且改动了它,原来父本里面的内容也被改变了。究其原因就是因为,Person里面的成员变量有一个是引用数据类型,它也指向堆区的一个对象,我们克隆person对象的时候,没有把这个引用指向的对象也克隆一分,导致父本和克隆的对象里面的money都指向了同一个对象,那么我们通过克隆的对象修改它成员所指向的对象,也会改变父本里面的内容。

    class Money {
        public double money = 12.5;
      /*  @Override
        protected Object clone() throws CloneNotSupportedException {
            return super.clone();
        }*/
    }
    class Person implements Cloneable {
        public String name;
         public Money money = new Money();
        public int a = 10;
    
        public Person(String name) {
            this.name = name;
        }
    
        @Override
        public String toString() {
            return "Person{" +
                    "name='" + name + '\'' +
                    '}';
        }
        //Object类的克隆方法。所有的类  默认继承与Object类
    
        @Override
        protected Object clone() throws CloneNotSupportedException {
            //return super.clone();
            return super.clone();
           /* Person personClone = (Person) super.clone();
            personClone.money = (Money)this.money.clone();
            return personClone;*/
        }
    
    }
    
    public  class TestDemo1 {
        public static void main(String[] args) throws CloneNotSupportedException {
            Person person = new Person("lmm");
            Person person2 = (Person)person.clone();
            System.out.println(person.money.money);
            System.out.println(person2.money.money);
            System.out.println("=========================");
            person2.money.money = 99;
            System.out.println(person.money.money);
            System.out.println(person2.money.money);
        }
    }
    

    也可以在看看图理解下:
    在这里插入图片描述
    所以如何修改实现深拷贝,对于这种情况,首先拷贝出person2,再把 person的成员里面的那个引用成员变量所指向的对象再拷贝一份之后person2的money指向拷贝出的引用指向的对象简单的说就是拷贝的对象和父本各自拥有各自的成员变量,不能共用成员变量,特别是当成员变量里面有引用数据类型的时候。代码如下:

    class Money implements Cloneable{
        public double money = 12.5;
        @Override
        protected Object clone() throws CloneNotSupportedException {
            return super.clone();
        }
    }
    
    @Override
        protected Object clone() throws CloneNotSupportedException {
            //return super.clone();
           // return super.clone();
            Person personClone = (Person) super.clone();
            personClone.money = (Money)this.money.clone();
            return personClone;
        }
    

    最后实现下面的结果:
    在这里插入图片描述
    我的第一次1024,大家节日快乐呀呀。谢谢支持
    在这里插入图片描述

    展开全文
  • Clonable接口和深拷贝

    2021-08-22 13:01:42
    对于数组的拷贝,如果是简单类型的话是深拷贝,如果是引用类型的话是浅... /*疑问:为什么这个接口是空接口呢?这是一个面试问题。 空节课:也把它叫做标记接口。其实就是这个意思:只要一个类实现了这个接口,那么就

    对于数组的拷贝,如果是简单类型的话是深拷贝,如果是引用类型的话是浅拷贝,但是因为java是面向对象的,在回答面试官问题的时候,我们可以不用说的这么细,可以直接说浅拷贝。

    代码示例1

    class Person implements Cloneable{//如果想克隆自定义类,那么需要在自定义类上实现Cloneable接口
        public int age;
        /*疑问:为什么这个接口是空接口呢?这是一个面试问题。
        空节课:也把它叫做标记接口。其实就是这个意思:只要一个类实现了这个接口,那么就标记这个类是可以进行clone的
        *
        * 2:重写clone方法*/
        @Override
        protected Object clone() throws CloneNotSupportedException {//重写了父类的克隆方法
            return super.clone();
        }
    }
    public class TestDemo {
        public static void main(String[] args) throws CloneNotSupportedException {
            Person person1 = new Person();
            Person person2 = (Person) person1.clone();
            System.out.println(person1.age);
            System.out.println(person2.age);
            System.out.println("=======修改=======");
            person2.age = 99;
            System.out.println(person1.age);
            System.out.println(person2.age);
        }
        /*public static void main(String[] args) {
            int[] array = {1,2,3,4,5,6};
            int[] array2 = array.clone();//对这个数组进行克隆
            array2[0] = 33;//改变拷贝后的数组元素的值不会影响原来数组的元素,这种情况是深拷贝
            System.out.println(Arrays.toString(array2));
            System.out.println(Arrays.toString(array));
        }*/
    }
    
    

    输出为:
    在这里插入图片描述
    因为改变的是简单类型,所以这种情况是深拷贝。

    代码示例2

    class Money{
        double money = 12.5;
    }
    class Person implements Cloneable{//如果想克隆自定义类,那么需要在自定义类上实现Cloneable接口
        public int age;
        /*疑问:为什么这个接口是空接口呢?这是一个面试问题。
        空节课:也把它叫做标记接口。其实就是这个意思:只要一个类实现了这个接口,那么就标记这个类是可以进行clone的
        *
        * 2:重写clone方法*/
        Money m = new Money();
    
        @Override
        protected Object clone() throws CloneNotSupportedException {//重写了父类的克隆方法
            return super.clone();
        }
    }
    public class TestDemo {
        public static void main(String[] args) throws CloneNotSupportedException {
            Person person1 = new Person();
            Person person2 = (Person) person1.clone();
            System.out.println(person1.m.money);
            System.out.println(person2.m.money);
            System.out.println("=========修改==========");
            person2.m.money = 99.9;
            System.out.println(person1.m.money);
            System.out.println(person2.m.money);
        }
    }
    

    输出为:
    在这里插入图片描述
    可以参考以下图分析:
    在这里插入图片描述
    这种情况就是浅拷贝,那么可以将这个浅拷贝变成深拷贝吗?只需要将Money也克隆一下

    class Money implements Cloneable{//如果想要变成深拷贝的话,那么money也需要被克隆。
        double money = 12.5;
    
        @Override
        protected Object clone() throws CloneNotSupportedException {
            return super.clone();
        }
    }
    class Person implements Cloneable{//如果想克隆自定义类,那么需要在自定义类上实现Cloneable接口
        public int age;
        Money m = new Money();
    
        @Override
        protected Object clone() throws CloneNotSupportedException {//重写了父类的克隆方法
            Person p = (Person)super.clone();//1:将当前的对象克隆一份,克隆person
            p.m = (Money) this.m.clone();//2:克隆当前的Money对象
            return p;
        }
    }
    public class TestDemo {
        public static void main(String[] args) throws CloneNotSupportedException {
            Person person1 = new Person();
            Person person2 = (Person) person1.clone();
            System.out.println(person1.m.money);
            System.out.println(person2.m.money);
            System.out.println("=========修改==========");
            person2.m.money = 99.9;
            System.out.println(person1.m.money);
            System.out.println(person2.m.money);
        }
    }
    

    输出为:
    在这里插入图片描述
    这样就就将浅拷贝转变成了深拷贝,可以参考以下图分析:
    在这里插入图片描述

    展开全文
  • 原型模式prototype package java_233_GOF23设计模式_原型模式_prototype_浅复制_深复制_Clonable接口_练习; import java.util.Date; /** Sheep羊 */ public class Sheep implements Cloneable {//Cloneable可复制的,...

    原型模式prototype
    在这里插入图片描述
    package java_233_GOF23设计模式_原型模式_prototype_浅复制_深复制_Clonable接口_练习;

    import java.util.Date;

    /**

    • Sheep羊
      */
      public class Sheep implements Cloneable {//Cloneable可复制的,可克隆的;一个接口
      //2个属性
      private String sname;//名字
      private Date birthday;//生日
      //重写方法
      @Override
      protected Object clone() throws CloneNotSupportedException {
      //clone是Object里面的一个方法;
      Object obj = super.clone();//直接调用Object对象的clone()方法
      return obj;
      //return super.clone();//可以用上面的替代
      }
      //get与set方法
      public String getSname() {
      return sname;
      }
      public void setSname(String sname) {
      this.sname = sname;
      }
      public Date getBirthday() {
      return birthday;
      }
      public void setBirthday(Date birthday) {
      this.birthday = birthday;
      }

      //构造器
      public Sheep() {
      super();
      }
      public Sheep(String sname, Date birthday) {
      super();
      this.sname = sname;
      this.birthday = birthday;
      }
      }
      //---------------------测试-浅克隆---------------------------------
      package java_233_GOF23设计模式_原型模式_prototype_浅复制_深复制_Clonable接口_练习;

    import java.util.Date;

    /**

    • 测试原型模式(浅克隆)
      */
      public class Client {
      public static void main(String[] args) throws CloneNotSupportedException {
      Date date = new Date(12312321331L);
      Sheep s1 = new Sheep(“少利”,date );//随意起的名字及时间
      System.out.println(s1);

       //创建新羊
       Sheep  s2 = (Sheep) s1.clone();//通过调用克隆方法;强制转型并抛出异常
       System.out.println(s2);
       
       System.out.println("====对象不一样但值一样===");
       System.out.println(s1.getSname());
       System.out.println(s1.getBirthday());
       System.out.println(s2.getSname());
       System.out.println(s2.getBirthday());
       
       //修改
       System.out.println("====修改s2的值===");
       s2.setSname("多利");
       System.out.println(s2);
       System.out.println(s2.getSname());
       System.out.println(s2.getBirthday());
       
       //修改时间
       System.out.println("====修改时间:s2的时间同s1的时间一样变化;指向同一对象===");
       date.setTime(23432432423L);
       System.out.println(s1.getBirthday());
       System.out.println(s2.getBirthday());
      

      }
      }
      //结果-------------------------------------------------------
      在这里插入图片描述

    //----------------------测试-深克隆-----------------------
    package java_233_GOF23设计模式_原型模式_prototype_浅复制_深复制_Clonable接口_练习;

    import java.util.Date;

    /**

    • Sheep羊
      */
      public class Sheep2 implements Cloneable {//Cloneable可复制的,可克隆的;一个接口
      //2个属性
      private String sname;//名字
      private Date birthday;//生日
      //重写方法
      @Override
      protected Object clone() throws CloneNotSupportedException {
      //clone是Object里面的一个方法;
      Object obj = super.clone();//直接调用Object对象的clone()方法

       **//添加如下代码实现深克隆(deep Clone)**
       Sheep2   s = (Sheep2) obj; //转型
       s.birthday = (Date) this.birthday.clone();//把属性进行克隆
       
       return obj;
       //return super.clone();//可以用上面的替代
      

      }
      //get与set方法
      public String getSname() {
      return sname;
      }
      public void setSname(String sname) {
      this.sname = sname;
      }
      public Date getBirthday() {
      return birthday;
      }
      public void setBirthday(Date birthday) {
      this.birthday = birthday;
      }

      //构造器
      public Sheep2() {
      super();
      }
      public Sheep2(String sname, Date birthday) {
      super();
      this.sname = sname;
      this.birthday = birthday;
      }
      }
      //--------------------测试原型模式(深克隆)----------------------------
      package java_233_GOF23设计模式_原型模式_prototype_浅复制_深复制_Clonable接口_练习;

    import java.util.Date;

    /**

    • 测试原型模式(深克隆)
      */
      public class Client2 {
      public static void main(String[] args) throws CloneNotSupportedException {
      Date date = new Date(12312321331L);
      Sheep2 s1 = new Sheep2(“少利”,date );//随意起的名字及时间
      //创建新羊
      Sheep2 s2 = (Sheep2) s1.clone();//通过调用克隆方法;强制转型并抛出异常 ;实现克隆:s2对象的birthday是一个新对象

       System.out.println(s1);
       System.out.println(s1.getSname());
       System.out.println(s1.getBirthday());
       
       //修改时间
       date.setTime(23432432423L);
       System.out.println(s1.getBirthday());
       
       s2.setSname("多利");
       System.out.println(s2);
       System.out.println(s2.getSname());
       System.out.println("===修改s1时间并不影响克隆后的s2时间===");
       System.out.println(s2.getBirthday());	
      

      }
      }
      //-------------------结果--------------------------------------
      在这里插入图片描述
      对比图
      在这里插入图片描述

    展开全文
  • 实现 implements Cloneable接口,因为Object没有实现Cloneable接口 package com.hou.pojo; //object类本身并没有实现Cloneable这个接口,所以需要我们自己进行实现 public class User extends Object implements ...
  • Cloneable接口的作用与深入理解深度克隆与浅度克隆

    万次阅读 多人点赞 2018-07-23 21:54:22
    cloneable接口的作用 cloneable其实就是一个标记接口,只有实现这个接口后,然后在类中重写Object中的clone方法,然后通过类调用clone方法才能克隆成功,如果不实现这个接口,则会抛出CloneNotSupportedException...
  • cloneable接口有什么用,浅拷贝和深拷贝你知道吗?
  • 深拷贝和浅拷贝

    2021-11-28 22:20:25
    文章目录浅拷贝和深拷贝浅拷贝的实现方法实现方式实现Clonable接口,重写clone方法序列化方式 浅拷贝和深拷贝 ​ 在Java语言中如果我们想要拷贝一个对象,有两种拷贝方式深拷贝和浅拷贝 浅拷贝在拷贝的时候只复制了...
  • Java中实现了Cloneable接口的类有很多,像我们熟悉的ArrayList、Calendar、Date、HashMap、Hashtable、HashSet、LinkedList等等。 还是那句话,对于不熟悉的接口、方法,第一反应一定是查询JDK API。 1、...
  • 1、实现Cloneable接口表明该类的对象是允许克隆的。 2、允许克隆的意思是:可以调用clone()方法。 3、深拷贝还是浅拷贝,取决于如何重写Object的clone()方法。 4、原对象和克隆对象的关系: 深拷贝:阳关道和独...
  • 首先做出回答:因为如果不继承自Cloneable接口,当调用clone()时会抛出CloneNotSupportedException异常 以下是详细讲解: class CloneClass implements Cloneable{  public int aInt;  public Object clone(){ ...
  • 一个类如果想重写 Object 的 clone 方法,则必须实现 Cloneable 接口,否则调用 clone 方法时将会抛出 CloneNotSupportException 异常 /** * Author: heatdeath * Date: 2018/7/7 * Desc: */ public class ...
  • 实现Cloneable接口,重写clone方法

    千次阅读 2013-12-25 23:42:51
    如果一个类精心设计了clone方法,那么clone方法就会完成对象的深拷贝。这里的精心设计指下面括号中的内容:(不管什么类,实现clone方法的第一步是调用super.clone()完成其父类的深拷贝和该类对象本身的浅拷贝。...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,666
精华内容 666
关键字:

clonable接口