接口的使用案例

介绍两个接口

下面将会介绍到:Comparable接口和 Cloneable这两个接口;

Comparable接口

重新认识sort()方法

要求:给对象数组进行排序

说到排序,我们就能想到之前所学的Arrays.Sort()方法,那接下来我们就来看一下该方法能否成功对对象数组进行排序呢?往下看

(1) 定义一个学生类

先对整形数组进行一个排序,结果如下:

import java.util.Arrays;

public class Student {
public static void main(String[] args) {
        // 定义一个整形数组
        int[] array1={2,3,1,5,6,8,7,4,9,0};
        Arrays.sort(array1);
        for(int i=0;i<array1.length;i++){
            System.out.print(array1[i]+" ");
        }
        System.out.println();
    }
}
 
 运行结果:
 0 1 2 3 4 5 6 7 8 9 

由上看出:得到的结果跟我们的预期是一样的!

那接下来我们就用该方法对学生对象进行排序~~

示例如下:

import java.util.Arrays;

public class Student {
    private String name;
    int score;

    public Student(String name, int score) {
        this.name = name;
        this.score = score;
    }
     public static void main(String[] args) {
        Student[] array2={new Student("张三",87),
                          new Student("李四",89),
                          new Student("王五",67),
                          new Student("赵六",79)};
        Arrays.sort(array2);
        for(int i=0;i<array2.length;i++){
            System.out.println(array2[i]);
        }
    }
}

那结果跟我们想象的并不一致,不但没有排出结果,还报错了,报错信息如下:
在这里插入图片描述
那我们就来分析一下,为什么会报错呢?
原因:由于学生信息里面有多个字段,既有名字,又有成绩,采用sort()进行排序时,编译器并不知道依据什么来进行排序,因此会报错;也就是说,sort()并不能直接对自定义对象直接进行排序呢.

那如果我们还想用该方法进行排序,那怎么实现呢?请往下看:

实现的前提:保证学生对象是可以进行比较的,才能进行排序;

实现Java为我们提供了一个Comparable接口,只要实现这里面的compareTo()抽象方法,即可进行排序了;

代码如下:

import java.util.Arrays;

public class Student implements Comparable {
    private String name;
    int score;

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

    @Override
    public int compareTo(Object o) {
        Student s = (Student) o;
        //this :  表示当前对象
        //o: 表示要和this比较的对象
        if (score > s.score) {
            return 1;  // 1代表正的
        } else if (score < s.score) {
            return -1;
        } else {
            return 0;
        }
    }

    public static void main(String[] args) {
        Student[] array2 = {new Student("张三", 87),
                new Student("李四", 89),
                new Student("王五", 67),
                new Student("赵六", 79)};
        Arrays.sort(array2);
        for (int i = 0; i < array2.length; i++) {
            System.out.println(array2[i]);
        }
    }
}

结果:
day20211001.Student@1b6d3586
day20211001.Student@4554617c
day20211001.Student@74a14482
day20211001.Student@1540e19d

运行后,虽然没有报错,但结果还是跟我们预想的不一样,打印的并不是不是对象中的内容,而是这样一串类似地址的值,那是因为在打印时,会调用Object类中的toString()方法,所以需要重写该方法;

**重写toString()`方法**

 @Override
    public String toString() {
        String s=new String("[");
        s+=name;
        s+=",";
        s+=score;
        s+="]";
        return s;
    }

重写完成之后,再运行,就可以看到我们想要的结果了,如下所示:

[王五,67]
[赵六,79]
[张三,87]
[李四,89]

由上面我们会发现,编译器是按照升序的顺序给我们进行打印的,如果想要降序进行排列,只需要将上面compareTo()方法下的正负1互相倒换一下即可;

以上都是Java系统给我们提供的sort()方法,接下来模拟实现sort()方法;

如下所示:采用之前所写的冒泡排序法,让能够实现Comparable接口的的,都可以进行排序;

思路:用外层循环控制冒泡的趟数,里层循环控制冒泡的方式;

public class Student implements Comparable {
    private String name;
    int score;

    public Student(String name, int score) {
        this.name = name;
        this.score = score;
    }
   @Override
    public int compareTo(Object o) {
        Student s = (Student) o;
        //this :  表示当前对象
        //o: 表示要和this比较的对象
        if (score > s.score) {
            return 1;  // 1代表正的
        } else if (score < s.score) {
            return -1;
        } else {
            return 0;
        }
    }
    public static void sort(Comparable[] stu){
        for(int i=0;i<stu.length-1;i++){
            for(int j=0;j<stu.length-i-1;j++){
            //比较的方式:compareTo()
                if(stu[j].compareTo(stu[j+1])>0){
                    Comparable temp=stu[j];
                    stu[j]=stu[j+1];
                    stu[j+1]=temp;
       }
     }
   }
 }
  @Override
    public String toString() {
        String s=new String("[");
        s+=name;
        s+=",";
        s+=score;
        s+="]";
        return s;
    }
    public static void main(String[] args) {
    Student[] array2 = {new Student("张三", 87),
                new Student("李四", 89),
                new Student("王五", 67),
                new Student("赵六", 79)};
        //Arrays.sort(array2);
        Student.sort(array2);
        for (int i = 0; i < array2.length; i++) {
            System.out.println(array2[i]);
        }
    }
}


然后,调用 Student.sort(array2);同样可以看到与上面相同的输出结果;

[王五,67]
[赵六,79]
[张三,87]
[李四,89]

(1)上面代码中的一个逻辑关系就是Student类重写了Comparable中的compareTo抽象方法;
(2)要想打印对象中的内容,就要调用Object类中的toString()方法;
(3)涉及到的Object类,是所有类的一个基类(可以通过IDEA去查看);
在这里插入图片描述

注意两个点

利用sort方法对自定义类型对象进行排序时:
(1)需要先实现Comparable接口;
(2)在该类中需要重写Comparable中的compareTo抽象方法;

Cloneable 接口

认识深浅拷贝(只针对自定义类型)

完成对象与对象之间的拷贝:Cloneable 接口

拷贝简单可以分为两种:
(1)浅拷贝:拷贝引用,不拷贝内容

new一个s1学生对象,然后再new一个s2对象,并将s1指向s2,简单来说,其实就是将s1的引用赋给了s2,使两个对象指向同一个内存空间,也就是使两个引用变量实际引用的是同一份对象;

**注意**:没有拷贝对象的内容(name,score),只是拷贝了引用;

public static void main(String[] args) {
        Student s1 =new Student("张三",90);
        Student s2=s1;

在这里插入图片描述
导致的后果

当一个人的成绩被修改之后,另一个人的成绩也随之被更改了;

public static void main(String[] args) {
        Student s1 =new Student("张三",90);
        Student s2=s1;
        s1.score=99;
        System.out.println(s2);
    }


 运行结果:
[张三,99]

浅拷贝存在这样的问题,那要改变这种不想要的结果,所以就需要研究深拷贝了,接下来看一下
深拷贝

(2)深拷贝:将实际对象中的内容拷贝了一份,行成一个新的对象;

谈到深拷贝,就需要讨论Cloneable这个接口了;

(1) Cloneable 接口的使用

首先,定义一个Person类,让该类去实现Cloneable这个接口;然后,使用快捷键crtl+左键,进入到该方法体中,但发现里面并没有任何的抽象方法;对于之前的理解,接口就是一个规范,既然里面没有抽象方法,那我们就不用实现它;

Cloneable接口里面:
在这里插入图片描述

(2)对 Clone() 方法进行重写(crtl+o)

上面已经说了,Object 类是所有类的一个基类,该类中存在一个 clone() 方法, 调用该方法就可以拷贝一个对象的,使用crtl+o进行重写,但重写完成之后,还需要改动三个地方:
第一,将修饰权限改为public

原因:因为重写的目的就是为了在类外进行调用,所以,需要修改权限修饰符;

第二,将类名Object改为本类名称;

原因:clone()方法被Person类重写了,拷贝出来的对象是一个Person对象;

第三,将返回值类型强制转换为本类类型;

在这里插入图片描述
修改之后结果如下:

   @Override
    public Person clone() throws CloneNotSupportedException {
        return (Person)super.clone();
    }

(3)调试运行整个代码

public class Person {
    private String name;
    int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public Person clone() throws CloneNotSupportedException {
        return (Person)super.clone();
    }


    public static void main(String[] args) throws CloneNotSupportedException {
        Person p1 =new Person("lilei",19);
        Person p2=p1;


        p2.age=20;
        System.out.println(p1.age);

        Person p3=p1.clone();
        p3.age=21;
        System.out.println(p1.age);
        System.out.println(p2.age);
        System.out.println(p3.age);;
    }
}

我们会发现:该段代码会抛出异常信息,异常信息如下:那为什么会这样呢?在这里插入图片描述
原因其实很简单:就是没有实现Cloneable接口,虽然它里面没有抽象方法,但在这里相当于是一个标志,实现了它,代码就可以正常运行了;

public class Person implements Cloneable{
 // 下面均是相同的  

但会发现运行调试之后,对象里面的内容并没有发生改变,因此这种方式仍然是浅拷贝结果如下
在这里插入图片描述
也就是说,直接使用clone()这个方法,并不能实现深拷贝,那要怎么样实现深拷贝呢?其实也不难,就是要将该类中的引用类型一层一层的实现cloneable接口并重写clone()方法,直到最后只剩下基本类型,就实现深拷贝了。

代码如下

class Money implements  Cloneable{
    double d=12.34;

    @Override
    public  Money clone() throws CloneNotSupportedException {
        return (Money)super.clone();
    }
}

public class Test implements  Cloneable{
    int num;
    Money m;

    public Test(){
        num=100;
        m=new Money();
    }

    @Override
    public Test clone() throws CloneNotSupportedException {
        Test t=(Test)super.clone();
        t.m=m.clone();
        return t;
    }

    public static void main(String[] args) throws CloneNotSupportedException {
        Test t1=new Test();
        Test t2=t1.clone();

        t1.m.d=100;
    }
}

调试运行,就可以看到如下结果,这样才真正实现了深拷贝
在这里插入图片描述
仔细体会》

想要各位大佬给个宝贵的意见共勉~~

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值