• Java—— 中的 Comparable、Clonable


    Java—— 中的 Comparable、Clonable

    在这里插入图片描述


    每博一文案

    这世间有太多的事与愿违,生命本身就是一座孤岛,人潮拥挤
    你来我往,是你的跑不掉,不是你的留不住,别去打扰,
    敷衍你的人,难受的始终是你自己。
    有段话好现实,你冷落了我。
    我也会慢慢的冷落你,我能习惯有你的陪伴,
    也能习惯没有你的孤单,失去的东西,其实从未有真正的属于你。
    所以不必感到惋惜。
    请你相信,总有人会捡起失落无助的你,
    然后安安稳稳地爱着你,
    这世上没有谁离不开谁,只有谁更在乎谁。
    珍惜你的人,不抛弃,无视你的人,就远离
    美好如你,值得这世间所有的美好。
                                ——————————————    一禅灵心庙语
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13


    Comparable

    • 我们先对一个简单的数组排序,看看使用的是何种方式
    import java.util.Arrays;
    
    public class Blog07 {
        public static void main(String[] args) {
            int[] arr = new int[]{100,250,36,46,55,66};
    
            Arrays.sort(arr); // 升序排序数组
    
            System.out.println(Arrays.toString(arr));
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    运行结果

    在这里插入图片描述


    • 我们在的小脑瓜,思考思考,看看我们的定义的类类性,是否也可以这样呢
    import java.util.Arrays;
    
    class Student {
        public String name;
        public int age;
        public int score;
    
        public Student(String name, int age,int score) {
            this.name = name;
            this.age = age;
            this.score = score;
    
        }
    
        @Override // 重写,注解:提示错误,人和编译器都可以读懂的注释
        public String toString() {
            return "Student{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    ", score=" + score +
                    '}';
        }
    }
    
    
    public class Blog07 {
        public static void main(String[] args) {
            Student student = new Student("小明",17,89);
            Student student1 = new Student("小红",18,90);
            Student student2 = new Student("小华",18,100);
    
            Student[] students = new Student[] {  // 创建该类 Student类的数组
                    student,
                    student1,
                    student2
            };
    
    
            Arrays.sort(students);  // 试试 使用Arrays.sort()对 自定义的类的数组排序
    
            System.out.println(Arrays.toString(students)); // 一字符串的形式打印数组
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    运行的错误结果

    在这里插入图片描述


    • 答案 ”是“ 不可以的 我什么会出现报错的情况,我们仔细思考一下,不难发现,和普通的整数不一样的地方,两个整数之间是可以直接比较出大小的,大小关系是明确的,而我们自行定义的 学生 对象的大小的关系,是无法直接确定的如下:
    class Student {
        public String name;
        public int age;
        public int score;
    
        public Student(String name, int age,int score) {
            this.name = name;
            this.age = age;
            this.score = score;
    
        }
    
        @Override // 重写,注解:提示错误,人和编译器都可以读懂的注释
        public String toString() {
            return "Student{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    ", score=" + score +
                    '}';
        }
    }
    
    public class Blog07 {
        public static void main(String[] args) {
            Student student = new Student("小明",17,89);
            Student student1 = new Student("小红",18,90);
            Student student2 = new Student("小华",18,100);
    
            if(student < student1) {
                System.out.println("sudent < sudent1");
            }   
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    运行错误结果

    在这里插入图片描述


    • 从结果上我们可以知道,该我们自定义的 Student 的类类型是无法自行比较的,其实: 一般情况下:自定义类型的比较,需要我们自行定义 额外 指定比较的方式,所以这里就用到的我们的 主体 :Comparable 让我们的 Student 类实现 Comparable 接口, 并实现其中的 compareTo 方法
    • 如下是 Comparable 的源码: 我们可以看到该 接口中 只有一个 public int compareTo(T o);抽象方法 ,我们实现该接口重写 该抽象类, 我们可以使用快捷键 Ctrl + i
    public interface Comparable<T> {
        /**
         * Compares this object with the specified object for order.  Returns a
         * negative integer, zero, or a positive integer as this object is less
         * than, equal to, or greater than the specified object.
         *
         * <p>The implementor must ensure <tt>sgn(x.compareTo(y)) ==
         * -sgn(y.compareTo(x))</tt> for all <tt>x</tt> and <tt>y</tt>.  (This
         * implies that <tt>x.compareTo(y)</tt> must throw an exception iff
         * <tt>y.compareTo(x)</tt> throws an exception.)
         *
         * <p>The implementor must also ensure that the relation is transitive:
         * <tt>(x.compareTo(y)&gt;0 &amp;&amp; y.compareTo(z)&gt;0)</tt> implies
         * <tt>x.compareTo(z)&gt;0</tt>.
         *
         * <p>Finally, the implementor must ensure that <tt>x.compareTo(y)==0</tt>
         * implies that <tt>sgn(x.compareTo(z)) == sgn(y.compareTo(z))</tt>, for
         * all <tt>z</tt>.
         *
         * <p>It is strongly recommended, but <i>not</i> strictly required that
         * <tt>(x.compareTo(y)==0) == (x.equals(y))</tt>.  Generally speaking, any
         * class that implements the <tt>Comparable</tt> interface and violates
         * this condition should clearly indicate this fact.  The recommended
         * language is "Note: this class has a natural ordering that is
         * inconsistent with equals."
         *
         * <p>In the foregoing description, the notation
         * <tt>sgn(</tt><i>expression</i><tt>)</tt> designates the mathematical
         * <i>signum</i> function, which is defined to return one of <tt>-1</tt>,
         * <tt>0</tt>, or <tt>1</tt> according to whether the value of
         * <i>expression</i> is negative, zero or positive.
         *
         * @param   o the object to be compared.
         * @return  a negative integer, zero, or a positive integer as this object
         *          is less than, equal to, or greater than the specified object.
         *
         * @throws NullPointerException if the specified object is null
         * @throws ClassCastException if the specified object's type prevents it
         *         from being compared to this object.
         */
        public int compareTo(T o);  
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 让我们的 Student 类实现 Comparable 接口, 并实现其中的 compareTo 方法 就可以比较了
    class Student implements Comparable <Student> {  // 实现 Comparable 接口
        public String name;
        public int age;
        public int score;
    
        public Student(String name, int age,int score) {
            this.name = name;
            this.age = age;
            this.score = score;
    
        }
    
        @Override // 重写,注解:提示错误,人和编译器都可以读懂的注释
        public String toString() {
            return "Student{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    ", score=" + score +
                    '}';
        }
    
        @Override // 重写 该 Comparable接口中的抽象类 compareTo
        public int compareTo(Student o) {
            if(this.score > o.score) { // 根据类中的成句比较,排序
                return 1;
            } else if(this.score == o.score) {
                return 0;
            } else {
                return -1;
            }
        }
    }
    
    public class Blog07 {
        public static void main(String[] args) {
            Student student = new Student("小明",17,89);
            Student student1 = new Student("小红",18,90);
            Student student2 = new Student("小华",18,100);
    
            if(student.compareTo(student1) < 0) {
                System.out.println("sudent < sudent1");
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    运行结果

    在这里插入图片描述


    • 我们再验证一下使用,数组的排序方法:Arrays.sort( ) ,看看是否会排序了
    import java.util.Arrays;
    
    class Student implements Comparable <Student> {  // 实现 Comparable 接口
        public String name;
        public int age;
        public int score;
    
        public Student(String name, int age,int score) {
            this.name = name;
            this.age = age;
            this.score = score;
    
        }
    
        @Override // 重写,注解:提示错误,人和编译器都可以读懂的注释
        public String toString() {
            return "Student{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    ", score=" + score +
                    '}';
        }
    
        @Override // 重写 该 Comparable接口中的抽象类 compareTo
        public int compareTo(Student o) {
            if(this.score > o.score) {  // 根据类中的成句比较,排序
                return 1;
            } else if(this.score == o.score) {
                return 0;
            } else {
                return -1;
            }
        }
    }
    
    public class Blog07 {
        public static void main(String[] args) {
            Student student = new Student("小明",17,89);
            Student student1 = new Student("小红",18,90);
            Student student2 = new Student("小华",18,100);
    
            Student[] students = new Student[] {  // 创建该类 Student类的数组
                    student,
                    student1,
                    student2
            };
    
            Arrays.sort(students);
    
            System.out.println(Arrays.toString(students));
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52

    运行结果

    在这里插入图片描述


    解析

    • 其实我们在 sort 方法中会自动调用 compareTo 方法,其中compareTo 的参数是 Object(祖类) ,其实传入的就是 Student 类型的对象。
      • 然后比较当前对象的分数和参数对象的的分数大小关系 (这里我们是以分数来比较计算大小的)
      • 如果当前对象的分数应排在参数对象的分数之前,返回小于 0 的数字;
      • 如果当前对象的分数应排在参数对象的分数之后,返回大于 0 的数字;
      • 如果当前对象的分数和参数的分数不分先后,返回 0;
    • 注意事项 对于 sort 方法来说,需要传入的数组的每个对象都是 ”可比较“ 的,需要具备 comparTo 这样的能力,通过重写其中的抽象方法 compareTo 的方式,就可以自行定义比较规则了。

    Clonable 接口和深拷贝

    • 首先我们先理解一下 什么是深拷贝,以及 深拷贝浅拷贝 的区别

      • 深拷贝 ,就是一种彻底的拷贝,克隆,就是拷贝后的对象的地址是,与原来拷贝对象的地址是不同的,是重新生成的一块地址空间的
      • 浅拷贝 ,就是一种比较不彻底的拷贝,克隆,就是拷贝后的对象的地址是,与原来拷贝对象的地址是一样的。只是对该拷贝对象的地址的一种指向的引用,其实,Java基本都是浅拷贝的 ,因为Java讲究的是 面向对象编程

    在这里插入图片描述


    • 如果想要克隆,深拷贝 自定义类类型,需要使用:Clonable 接口

    • Object(祖类) 中存在一个 clone 方法,调用这个方法可以创建一个对象的 ”拷贝“ ,但是要想用 clone 方法拷贝,克隆我们自定义类类型,必须要先 实现 Clonable 接口 的接口,否则就会抛出 **CloneNotSupportedException ** 异常

    • Cloneable的源码 如下:

    /**
     * A class implements the <code>Cloneable</code> interface to
     * indicate to the {@link java.lang.Object#clone()} method that it
     * is legal for that method to make a
     * field-for-field copy of instances of that class.
     * <p>
     * Invoking Object's clone method on an instance that does not implement the
     * <code>Cloneable</code> interface results in the exception
     * <code>CloneNotSupportedException</code> being thrown.
     * <p>
     * By convention, classes that implement this interface should override
     * <tt>Object.clone</tt> (which is protected) with a public method.
     * See {@link java.lang.Object#clone()} for details on overriding this
     * method.
     * <p>
     * Note that this interface does <i>not</i> contain the <tt>clone</tt> method.
     * Therefore, it is not possible to clone an object merely by virtue of the
     * fact that it implements this interface.  Even if the clone method is invoked
     * reflectively, there is no guarantee that it will succeed.
     *
     * @author  unascribed
     * @see     java.lang.CloneNotSupportedException
     * @see     java.lang.Object#clone()
     * @since   JDK1.0
     */
    public interface Cloneable {
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 我们通过 Cloneable的源码 可以看到,其中只有一个 空的接口:public interface Cloneable

    所谓的空接口:

    public interface Cloneable {

    }

    空接口也叫做 标记接口,其实就是字面意思,只要一个类,

    实现了这个接口,这里是 (public interface Cloneable) 接口,那么就标记这个类,是可以进行 clone 方法的使用的。


    class Persons implements Cloneable {
    
        public int age = 18;
    
        @Override // 对clone 的重写,
        protected Object clone() throws CloneNotSupportedException {
            return super.clone(); // 注意这里的 返回类型是 Object ,
        }
    
    }
    
    public class Blog07 {
        public static void main(String[] args) throws CloneNotSupportedException {
            Persons person = new Persons();
            Persons person2 = (Persons)person.clone(); // 将 Object类类型 强转为 Persons类类型,克隆,深拷贝
            System.out.println(person.age);
            System.out.println(person2.age);
    
            System.out.println("*******修改后******");
    
            person2.age = 99;
            System.out.println(person.age);
            System.out.println(person2.age);
    
            System.out.println("*******************");
            
            System.out.println(person);
            System.out.println(person2);
        }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    运行结果

    在这里插入图片描述


    该代码的核心结构图

    在这里插入图片描述


    • 我们在玩一个更有意思的,在一个类中包含一个类的类型,进行 深拷贝
    class Money {
        public int money = 10;
    }
    
    class Persons implements Cloneable {
    
        public int age = 18;
        
        Money moneys = new Money();
    } 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 我们先试试,原来的方式,是否可以,完成对应的 深拷贝
    class Money {
        public int money = 10;
    }
    
    
    class Persons implements Cloneable {
    
        public int age = 18;
    
        Money moneys = new Money();
    
    
        @Override // 对clone 的重写,
        protected Object clone() throws CloneNotSupportedException {
            return super.clone(); // 注意这里的 返回类型是 Object ,
        }
    
    }
    
    public class Blog07 {
        public static void main(String[] args) throws CloneNotSupportedException {
            Persons person = new Persons();
            Persons person2 = (Persons)person.clone(); // 将 Object类类型 强转为 Persons类类型,克隆,深拷贝
    
            System.out.println("person.moneys.money: "+person.moneys.money);
            System.out.println("person2.moneys.money: "+person2.moneys.money);
    
            System.out.println("*******修改后******");
    
            person.moneys.money = 1000_000_000;
            System.out.println("person.moneys.money: "+person.moneys.money);
            System.out.println("person2.moneys.money: "+person2.moneys.money);
    
            System.out.println("*******************");
    
            System.out.println("person.moneys 地址: "+person.moneys);
            System.out.println("person2.moneys 地址: "+person2.moneys);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    运行结果

    在这里插入图片描述


    • 通过 运行的结果 我们可以十分肯定的知道,一个类中包含一个类类型的拷贝的 深拷贝 是不可以的
    • 结果图:如下
      在这里插入图片描述

    • 通过结果我们可以知道,我们类当中的类,也就是可以的 (moneys) 并没有被 深拷贝 到,我们可以对齐,同样的 cloable 接口的实现:
    class Money implements Cloneable {
        public int money = 10;
    
        @Override
        protected Object clone() throws CloneNotSupportedException {
            return super.clone(); // 注意这里的 返回类型是 Object ,
        }
    }
    
    
    class Persons implements Cloneable {
    
        public int age = 18;
    
        Money moneys = new Money();
    
    
        @Override // 对clone 的重写,
        protected Object clone() throws CloneNotSupportedException {
    
            // 克隆 person
            Persons p = (Persons)super.clone(); // 将 Persons 中克隆(clone())的返回类类型,Object类类型强转为 Persons类类型
            // 克隆当前的 Money 对象
            p.moneys = (Money) this.moneys.clone(); // 将 Money中的克隆(clone())的返回类类型,Object类类型强转为 Money 类型
    
            return p;
        }
    
    }
    
    public class Blog07 {
        public static void main(String[] args) throws CloneNotSupportedException {
            Persons person = new Persons();
            Persons person2 = (Persons)person.clone(); // 将 Object类类型 强转为 Persons类类型,克隆,深拷贝
    
            System.out.println("person.moneys.money: "+person.moneys.money);
            System.out.println("person2.moneys.money: "+person2.moneys.money);
    
            System.out.println("*******修改后******");
    
            person.moneys.money = 1000_000_000;
            System.out.println("person.moneys.money: "+person.moneys.money);
            System.out.println("person2.moneys.money: "+person2.moneys.money);
    
            System.out.println("*******************");
    
            System.out.println("person.moneys 地址: "+person.moneys);
            System.out.println("person2.moneys 地址: "+person2.moneys);
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    运行结果

    在这里插入图片描述


    • 其中的结构图

    在这里插入图片描述


    最后:

    限于自身的水平,其中存在的错误,希望大家给予指教,韩信点兵——多多益善,谢谢大家,后会有期,江湖再见!

  • 相关阅读:
    Multiple CORS header ‘Access-Control-Allow-Origin‘ not allowed
    CentOS7自有服务和软件包
    SSM+校园社团平台 毕业设计-附源码251554
    116.(前端)商品管理删除实现——前端使用messagebox弹窗确认发送请求
    ctfshow XSS
    阿里巴巴找黄金宝箱(II)
    python分享之读取xml文件
    如何让设计师快速提高设计美感?这5个网站就够了
    与堆和堆排序相关的问题
    IDEA Error: java: -source 1.5中不支持 lambda 表达式和 Error:java: Compilation failed
  • 原文地址:https://blog.csdn.net/weixin_61635597/article/details/125629591