【JAVASE】三大常用接口与深拷贝(Comparable,Comparator,Clonable)

初见乍惊欢,久处亦怦然

【JAVASE】三大常用接口与深拷贝(Comparable,Comparator,Clonable)_第1张图片
大家好,这里是新一,请多关照。首先祝大家中秋团圆,在这中秋佳节,怎么不来一篇博客呢,接下来让我们了解一下JAVA三大常用接口和深拷贝吧。(以下结果均在IDEA中编译)希望在方便自己复习的同时也能帮助到大家。

废话不多说,直接进入我们的文章。


文章目录

  • 一. 三大接口
    • 1.1 Comparable接口
    • 1.2 Comparator接口
    • 1.3 Clonable接口
  • 二. 深拷贝
  • 想对大家说的话


一. 三大接口

此处我们以学生信息排序为例,给大家讲解一下这三大接口(Comparable
Comparator,Clonable)

1.1 Comparable接口

我们知道JAVA中可以用Arrays.sort对数组进行排序,例如我们对下列数组进行排序

public static void main1(String[] args) {
        int[] array = {1,21,3,14,5,16};
        Arrays.sort(array);
        System.out.println(Arrays.toString(array));
    }

其中的sort是根据数组元素的大小进行排序的,那么如果我们用Arrays.sort来排序复杂对象呢?如下

class Student implements Comparable<Student>{
    public int age;
    public String name;
    public double score;

    public Student(int age, String name, double score){
        this.age = age;
        this.name = name;
        this.score = score;
    }

    @Override
    public String toString() {
        return "Student{" +
                "age=" + age +
                ", name='" + name + '\'' +
                ", score=" + score +
                '}';
    }
}
public class Test {
    
    public static void main(String[] args) {
        Student[] students = new Student[3];
        students[0] = new Student(14,"张三",78.9);
        students[1] = new Student(13,"李四",86.9);
        students[2] = new Student(12,"王麻子",99.5);

        System.out.println(Arrays.toString(students));

        Arrays.sort(students);

        System.out.println(Arrays.toString(students));
    }
}

那么现在可以排序吗,那是肯定不行的,因为sort并不知道你要根据什么特性来排序,我们先来查看一下sort的底层代码

  1. 我们按住Ctrl并点击sort


2. 按住Ctrl点击legacyMerfeSort
【JAVASE】三大常用接口与深拷贝(Comparable,Comparator,Clonable)_第2张图片
3.按住Ctrl点击mergeSort

4. 此处我们发现这里有个compareTo函数,按住Ctrl并点击
【JAVASE】三大常用接口与深拷贝(Comparable,Comparator,Clonable)_第3张图片
我们发现这个函数是没有实现的,难道是意外吗?当然不是,我们再看看这个类
在这里插入图片描述
它是个Comparable接口,这个比较的函数CompareTo就需要我们自己来实现,如下:

//谁调用这个方法谁就是this
    @Override
    public int compareTo(Student o) {
        return this.age - o.age;//根据年龄排序
    }

在这里插入图片描述
那么我们如果需要按名字来排序呢?

class Student implements Comparable<Student>{
    public int age;
    public String name;
    public double score;

    public Student(int age, String name, double score){
        this.age = age;
        this.name = name;
        this.score = score;
    }

    @Override
    public String toString() {
        return "Student{" +
                "age=" + age +
                ", name='" + name + '\'' +
                ", score=" + score +
                '}';
    }
    //谁调用这个方法谁就是this
    @Override
    public int compareTo(Student o) {
        //return this.age - o.age;
        return this.name.compareTo(o.name);
    }
}


public class Test {
    
    public static void main(String[] args) {
        Student[] students = new Student[3];
        students[0] = new Student(14,"张三",78.9);
        students[1] = new Student(13,"李四",86.9);
        students[2] = new Student(12,"王麻子",99.5);

        System.out.println(Arrays.toString(students));

        Arrays.sort(students);

        System.out.println(Arrays.toString(students));
    }
}

没错,我们需要修改类里边的源码才能对排序特性进行修改,那么这样必然会存在一下问题,要知道,公司里边的源码是不能随便动的,因此,Comparable实现的接口有很大的缺陷 - 太嵌入

1.2 Comparator接口

那么有没有更好的方法来实现我们的sort结构体排序呢?当然有,那就是我们的Comparator接口
我们同样按住Ctrl再点击Comparator
【JAVASE】三大常用接口与深拷贝(Comparable,Comparator,Clonable)_第4张图片
既然这个是个接口,我们就需要重写其中的方法compare,调用这个接口并重写这个方法的类我们就称为比较器

class AgeComparstor implements Comparator<Student>{
    @Override
    public int compare(Student o1, Student o2) {
        return o1.age - o2.age;
    }
}

class ScoreComparstor implements Comparator<Student>{
    @Override
    public int compare(Student o1, Student o2) {
        return (int)(o2.score - o1.score);
    }
}
class NameComparstor implements Comparator<Student>{
    @Override
    public int compare(Student o1, Student o2) {
        return o1.name.compareTo(o2.name);
    }
}

此即为学生这个对象排序的三个比较器,那么怎么调用呢?

class Student {
    public int age;
    public String name;
    public double score;

    public Student(int age, String name, double score){
        this.age = age;
        this.name = name;
        this.score = score;
    }

    @Override
    public String toString() {
        return "Student{" +
                "age=" + age +
                ", name='" + name + '\'' +
                ", score=" + score +
                '}';
    }
}
class AgeComparstor implements Comparator<Student>{
    @Override
    public int compare(Student o1, Student o2) {
        return o1.age - o2.age;
    }
}

class ScoreComparstor implements Comparator<Student>{
    @Override
    public int compare(Student o1, Student o2) {
        return (int)(o2.score - o1.score);
    }
}
class NameComparstor implements Comparator<Student>{
    @Override
    public int compare(Student o1, Student o2) {
        return o1.name.compareTo(o2.name);
    }
}
public class Test {
    public static void main(String[] args) {
        Student[] students = new Student[3];
        students[0] = new Student(14,"张三",78.9);
        students[1] = new Student(13,"李四",86.9);
        students[2] = new Student(12,"王五",99.5);

        System.out.println(Arrays.toString(students));
        AgeComparstor ageComparstor = new AgeComparstor();
        ScoreComparstor scoreComparstor = new ScoreComparstor();
        NameComparstor nameComparstor = new NameComparstor();

        Arrays.sort(students,nameComparstor);

        System.out.println(Arrays.toString(students));
    }
}

我们只需要在main函数中new一个比较器对象,再将其加入到Arrays.sort方法中即可排序, Comparator对类的侵入性非常弱 ,故在一般情况下推荐这个接口

1.3 Clonable接口

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

class Person implements Cloneable{
    public int age;

    public void eat() {
        System.out.println("吃!");
    }

    @Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                '}';
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Person tmp = super.clone();
        return tmp;
    }
}
public class Clonable {
    
    public static void main(String[] args) throws CloneNotSupportedException {
        Person person = new Person();
        person.age = 99;
        Person person2 = (Person) person.clone();
        System.out.println(person2);

        System.out.println("===============");
        person2.age = 199;

        System.out.println(person);
        System.out.println(person2);
    }
}

此时我们会发现person2就是我们克隆的对象了,那么我们改变person2的值会影响person1吗,答案是否定的的,因为我们所实现的这个方法是所谓的深拷贝,它克隆了我们的这个对象,同样在堆区也就对了一份找个对象,两个对象互不影响

二. 深拷贝

在上述用例中我们实现的方法即为深拷贝,但并不是Clonable这个接口是深拷贝,是我们实现的这个方法是深拷贝,取决于我们如何实现的方法,那么为什么呢?我们再给个用例

class Money implements Cloneable{
    public double m = 12.5;
}
class Person implements Cloneable{
    public int age;
    public Money money = new Money();

    public void eat() {
        System.out.println("吃!");
    }

    @Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                '}';
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Person tmp = super.clone();
        return tmp;
    }
}
public class Clonable {
    public static void main(String[] args) throws CloneNotSupportedException {
        Person person = new Person();
        Person person2 = (Person) person.clone();
        System.out.println(person.money.m);
        System.out.println(person2.money.m);
        System.out.println("===================");
        person2.money.m = 99.99;
        System.out.println(person.money.m);
        System.out.println(person2.money.m);
    }
}

此时会发现当我们改变拷贝对象时,原对象也发生变化,这就说明对象并未被拷贝,而只是引用被拷贝了一份,因此这就叫浅拷贝
我们也可以把它变成深拷贝。

class Money implements Cloneable{
    public double m = 12.5;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();//拷贝引用对象
    }
}
class Person implements Cloneable{
    public int age;
    public Money money = new Money();//引用类型

    public void eat() {
        System.out.println("吃!");
    }

    @Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                '}';
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Person tmp = (Person)super.clone();
        tmp.money = (Money) this.money.clone();//调用方法拷贝对象
        return tmp;
    }
}
public class Clonable {
    public static void main(String[] args) throws CloneNotSupportedException {
        Person person = new Person();
        Person person2 = (Person) person.clone();
        System.out.println(person.money.m);
        System.out.println(person2.money.m);
        System.out.println("===================");
        person2.money.m = 99.99;
        System.out.println(person.money.m);
        System.out.println(person2.money.m);
    }
}

此时我们发现,实现了深拷贝。

想对大家说的话

家人们,学到这里我们已经学习完了三大接口与深拷贝了,也在这里祝大家节日快乐后续新一会持续更JAVA的有关内容,学习永无止境,技术宅,拯救世界!

【JAVASE】三大常用接口与深拷贝(Comparable,Comparator,Clonable)_第5张图片

你可能感兴趣的:(java专项突破,java,算法,数据结构)