Java接口的应用

news2024/10/6 20:36:03
  1. 目标:总结Comparable接口以及compareTo方法、comparator接口中compare方法比较器、toString方法、equals方法、hashCode方法、Cloneable接口以及深浅拷贝

  2. 比较对象中内容的大小【Comparable接口以及compareTo方法】
    例如:学生类:成员有姓名、年龄、分数
    要求:分别按照姓名、年龄、分数排序
    初步编写:
    学生类:

package demo2;

public 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 +
                '}';
    }
}

测试类:
package demo2;

import java.util.Arrays;

public class TestStudent {
public static void main(String[] args) {
Student[] students = new Student[3];
students[0] = new Student(“王王王”,21,98);
students[1] = new Student(“帅帅帅”,22,66);
students[2] = new Student(“哈哈哈”,23,99);

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

}

运行结果:抛出异常
在这里插入图片描述
分析:Arrays.sort(students);不知道怎么比较大小
根据报错提示:
在这里插入图片描述
在这里插入图片描述
作用:取到数组的某一个值,把这个值转换为一个Comparable接口类型,然后调用compareTo方法
在这里插入图片描述

因此在Student类中实现Comparable接口,并重写compareTo方法。

package demo2;

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

    @Override
    public int compareTo(Object o) {
    //向下转型,因为Object是所有类的父类,将Object父类转成Studnet子类
        Student s = (Student) o;
        if (this.age > s.age) {
            return 1;
        }else if (this.age < s.age) {
            return  -1;
        }else {
            return 0;
        }
    }

    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 +
                '}';
    }
}

运行结果:
在这里插入图片描述
分析:此时按照年龄从小到大排序。

        System.out.println(students[0].compareTo(students[1]));

让0下标的学生去调用compareTo方法去和1下标的学生进行比较,所以在compareTo方法中,this代表0下标的学生,传入的Object o,以及强制类型转换成Student s代表的是1下标的学生。
在这里插入图片描述
假如根据姓名比较,重写的compareTo方法相当于写了一个比较规则,从而sort也有用了

    public int compareTo(Object o) {
        Student s = (Student) o;
        if (this.name.compareTo(s.name) > 0) {
            return 1;
        }else if (this.name.compareTo(s.name) < 0) {
            return -1;
        }else {
            return 0;
        }
    }

运行结果:
在这里插入图片描述
分析:此处的name是String类型,String类型比较大小不能通过数学符号(>和<等)比较,要通过String类中的compareTo方法(String类也实现了Comparable接口,则必定也实现了compareTo方法),equals只能比较字符串相不相同(并且equals返回值的类型是boolean类型)

自己实现sort【采用冒泡排序】

    public static void sort(Comparable[] array) {
        for (int i = 0; i < array.length - 1; i++) {
            for (int j = 0; j < array.length - 1 -i; j++) {
                if (array[j].compareTo(array[j+1]) > 0) {
                    Comparable t = array[j];
                    array[j] = array[j+1];
                    array[j+1] = t;
                }
            }
        }
    }

注意:形参是Comparable接口类型,在if语句中的比较规则用到实现接口中的compareTo方法。

但是,目前这样写,用Comparable接口不好,因为代码不够灵活,一旦写死了拿年龄比较,以后默认都是拿年龄比较,那我要想拿名字或者分数比较就不行了。

  1. 比较对象中内容的大小【比较器Comparator接口中compare方法】
    刚刚是Student类实现Comparable接口重写compareTo方法,现在是新创建一个毫不相干的类实现Comparator接口。
    Comparator接口里面的抽象方法只有一个,所以新建一个AgeComparator类实现Comparator接口重写compare方法。
    在这里插入图片描述
    新建一个类实现接口并重写方法:
package demo4;

import java.util.Comparator;

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

实例化新建类的对象,并作为sort的第二个参数

    public static void main(String[] args) {
        Student[] students = new Student[3];

        students[0] = new Student("王王王",23,98);
        students[1] = new Student("帅帅帅",22,66);
        students[2] = new Student("哈哈哈",24,99);

        //既然是一个类,就在这里面实例化这个对象
        AgeComparator ageComparator = new AgeComparator();
        //把他传给sort的第二个参数
        Arrays.sort(students,ageComparator);
        System.out.println(Arrays.toString(students));
    }

分析: AgeComparator ageComparator = new AgeComparator(); 叫做比较器,这样实现比较就比较灵活。
比如想通过分数比较,可以新建一个分数的比较器:

package demo4;

import java.util.Comparator;

public class ScoreComparator implements Comparator <Student> {
    @Override
    public int compare(Student o1, Student o2) {
        return o1.score - o2.score;
    }
}
        ScoreComparator scoreComparator = new ScoreComparator();
        Arrays.sort(students,scoreComparator);

通过姓名比较:

package demo4;

import java.util.Comparator;

public class NameCompartor implements Comparator<Student> {
    @Override
    public int compare(Student o1, Student o2) {
        return (o1.name.compareTo(o2.name));
    }
}
        NameCompartor nameCompartor = new NameCompartor();
        Arrays.sort(students,nameCompartor);

以上就是非常灵活的比较器,想怎么写就怎么写。

  1. Object是Java默认提供的一个类,Java中Object类是所有类的父类,默认会继承Object父类,即所有类的对象都可以使用Object的引用进行接受
    Object类中有的方法
    在这里插入图片描述
  2. Object类中的toString方法
    在这里插入图片描述
    如果我们要打印对象中的内容,则需要在对象中重写toString方法。
    因为可以认为要重写的那个对象的父类一定是Object,因此重写toString
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", score=" + score +
                '}';
    }

①如果没有重写toString方法,运行结果:
在这里插入图片描述
②如果重写了toString方法,运行结果:
在这里插入图片描述

  1. Object类中的equals方法
    public boolean equals(Object obj) {
        return (this == obj);
    }

如果要比较对象中内容是否相同,必须重写Object中的equals方法,因为equals方法默认是按照地址比较的。
在创建2个对象,分别为(姓名和年龄都一样):
姓名:小王,年龄22;姓名:小王,年龄22

    public static void main(String[] args) {
        Student student1 = new Student("小王",22);
        Student student2 = new Student("小王",22);

        System.out.println(student1.equals(student2));
    }

①没有重写equals,运行结果:
在这里插入图片描述
分析:因为2个对象的姓名和年龄都相同,在主观现实世界中,我们会认为这2个对象是同一个对象,但是程序的运行结果却是flase,因此我们要重写Objec类中的equals方法。

②重写equals,运行结果:

   @Override
    public boolean equals(Object o) {

        if (this == o) {
            return true;
        }
        if (o == null) {
            return false;
        }

        if (! (o instanceof Student)) {
            return false;
        }

        Student s = (Student) o;
        if (this.name == s.name && this.age == s.age) {
            return true;
        }
        return false;
    }

运行结果:
在这里插入图片描述
编译器自动重写的equals方法:

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return age == student.age && Objects.equals(name, student.name);
    }
  1. Object类中的hashCode方法
    在上例中创建的2个学生类对象,我们认为2个对象是指同一个人(对象),所有在打印2个对象的地址的时候,理论上的运行结果应该是在内存中存同一个地址。
        System.out.println(student1);
        System.out.println(student2);

①没有重写hashCode方法的时候,运行结果:
在这里插入图片描述
②重写hashCode方法的运行结果:

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }

在这里插入图片描述
分析:通过name和age去返回哈希地址,因为student1和student2的name和age都相同,因此打印出来的地址也是相同的。
总结:hashcode方法用来确定对象在内存中存储的位置是否相同

  1. 要去克隆,则一定要实现Clonable接口
    在这里插入图片描述
    分析:克隆接口Cloneable时一个空接口,也叫标记接口,作用是:表示当前对象是可以被克隆的。
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
    public static void main(String[] args) throws CloneNotSupportedException  {
        Student student1 = new Student("小帅");
        Student student2 = (Student) student1.clone();
        System.out.println(student1);
        System.out.println(student2);

    }

整体代码:

package demo5;

class Student implements Cloneable{
    public String name;

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

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                '}';
    }
}

public class Test {
    //学习自定义类型克隆拷贝
    public static void main(String[] args) throws CloneNotSupportedException  {
        Student student1 = new Student("小帅");
        Student student2 = (Student) student1.clone();
        System.out.println(student1);
        System.out.println(student2);

    }
}

运行结果:
在这里插入图片描述
分析:目前是可以对自定义类型进行拷贝了,但是拷贝分为浅拷贝和深拷贝。

  1. 关于浅拷贝和深拷贝
    浅拷贝:修改拷贝的对象(副本),之前的本身也会改变。
    深拷贝: 修改拷贝的对象(副本),之前的本身不受影响。
    如图:本身是蓝色,拷贝后也是蓝色,如果用红色修改拷贝后的,原本身的也被会红色修改则是浅拷贝,原本身的不会被红色修改就是深拷贝。
    在这里插入图片描述
  2. 浅拷贝例子
    新建一个Money类
class Money {
    public double money = 12.5;
}

组合:每个学生都有钱,在Student类中实例化Money对象

class Student implements Cloneable{
    public String name;
    public Money m = new Money();

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

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", m=" + m +
                '}';
    }
}

测试:

public class Test {
    //学习自定义类型克隆拷贝
    public static void main(String[] args) throws CloneNotSupportedException  {
        Student student1 = new Student("小帅");
        Student student2 = (Student) student1.clone();
        System.out.println(student1.m.money);
        System.out.println(student2.m.money);
        student2.m.money = 99;
        System.out.println("修改拷贝对象的money之后的打印结果");
        System.out.println(student1.m.money);
        System.out.println(student2.m.money);
    }
}

运行结果:
在这里插入图片描述
分析:修改拷贝对象student2的值money,原来的student1的值也发生了改变,则是浅拷贝,因为只对student1拷贝,并没有把money也拷贝一份。
在这里插入图片描述

  1. 将上述例子改成深拷贝:即m所指的money对象也要克隆
    ①Money类实现Cloneable接口
class Money implements  Cloneable{
    public double money = 12.5;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

②Student类重写clone方法

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Student student = (Student) super.clone(); //得到一个浅拷贝对象
        student.m = (Money) this.m.clone(); //浅拷贝的对象的m要再次拷贝,从而实现深拷贝
        //this 谁调用这个方法就指谁,这里指student1
        return student;
    }

在这里插入图片描述
分析:此时实现了深拷贝,Student student = (Student) super.clone();只是克隆了student对象, student.m = (Money) this.m.clone();克隆了student对象里面的money对象。
在这里插入图片描述
所以如要要实现深拷贝,当前对象的每一个对象都要克隆。

  1. 使用Objetct接受所有类的对象,以及匿名对象的使用
package demo6;

class  Dog {
    
}


public class Test {
    public static void func(Object o) {
        System.out.println("wow");
    }
    
    public static void main(String[] args) {
      func(new Dog());
      Dog dog = new Dog();
      func(dog);
    }
}

所有类的对象都可以使用Object的引用进行接受public static void func(Object o)
当没有给其他引用的时候,这些都是匿名对象,形如: func(new Dog());即为匿名对象,缺点是每次使用都需要new,使用场景是只用一次的时候。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/20158.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

计算机网络4小时速成:数据链路层,功能,封装成帧,透明传输,差错控制,PPP协议,广播信道,以太网,MAC层,设备

计算机网络4小时速成&#xff1a;数据链路层&#xff0c;功能&#xff0c;封装成帧&#xff0c;透明传输&#xff0c;差错控制&#xff0c;PPP协议&#xff0c;广播信道&#xff0c;以太网&#xff0c;MAC层&#xff0c;设备 2022找工作是学历、能力和运气的超强结合体&#x…

Linux C/C++ 学习笔记(四):MYSQL安装与远程连接

问题及解决 对配置文件中绑定的IP地址进行修改 通过Mysql workbench连接MySQL数据库时出现错误 需要对mysq的配置文件进行修改&#xff0c;配置文件是/etc/mysql下的my.cnf 绑定的地址是一个回环地址&#xff0c;不能对外使用 将其修改为0.0.0.0。 0.0.0.0不是一个真正意义…

MySQL主从数据库(主读从写)

MySQL多数据源MySQL主从数据库&#xff08;主读从写&#xff09;1. 多数据源的实现原理1.1 配置多数据源yml文件1.2 创建配置类1.3 动态切换数据源类继承AbstractRoutingDataSource 类1.4 测试类测试1.5 附枚举代码1.6 总结2. 多数据源切换方式&#xff08;优化&#xff09;2.1…

HTML做一个简单漂亮的宠物网页(纯html代码) 带视频 带音乐 带报告

⛵ 源码获取 文末联系 ✈ Web前端开发技术 描述 网页设计题材&#xff0c;DIVCSS 布局制作,HTMLCSS网页设计期末课程大作业 | 宠物网页设计 | 保护动物网页 | 鲸鱼海豚主题 | 保护大象 | 等网站的设计与制作 | HTML宠物网页设计 | HTML期末大学生网页设计作业 HTML&#xff1a;…

酒水推荐商城|基于Springboot实现酒水商城系统

作者主页&#xff1a;编程指南针 作者简介&#xff1a;Java领域优质创作者、CSDN博客专家 、掘金特邀作者、多年架构师设计经验、腾讯课堂常驻讲师 主要内容&#xff1a;Java项目、毕业设计、简历模板、学习资料、面试题库、技术互助 收藏点赞不迷路 关注作者有好处 文末获取源…

FLP、CAP和BASE

FLP不可能原理 FLP定理 FLP Impossibility&#xff08;FLP 不可能性&#xff09;是分布式领域中一个非常著名的定理&#xff0c;定理的论文是由 Fischer, Lynch and Patterson 三位作者于1985年发表 It is impossible to have a deterministic protocol that solves consens…

通过WebSocket实现实时系统通知,以后再也不能装作没看到老板的通知了~~

&#x1f4de; 文章简介&#xff1a;WebSocket实时通知Demo &#x1f4a1; 创作目的&#xff1a;因为公司正在从零搭建CRM&#xff0c;其中有一个需求是系统通知管理&#xff0c;老板发布通知给员工。简单的用数据库实现感觉缺少一些实时性&#xff0c;不是那么生动。于是想到了…

向毕业妥协系列之深度学习笔记(三)DL的实用层面(上)

目录 一.训练_开发_测试集 二.方差与偏差 三.正则化 四.Dropout正则化 五.其他正则化方法 本篇文章大部分又是在ML中学过的&#xff0c;除了Dropout正则化及之后的部分。 一.训练_开发_测试集 在配置训练、验证和测试数据集的过程中做出正确决策会在很大程度上帮助大家创…

[Spring MVC 8]高并发实战小Demo

本项目基于Spring MVC进行关于点赞项目的开发&#xff0c;从传统的点赞到高并发缓存开发最后到消息队列异步开发&#xff0c;可谓是令人大开眼界。 本篇博客全部代码已经放出&#xff0c;本博客重点是后端操作&#xff0c;所以对于前端就十分简单的页面。讲述了关于Redis,Quart…

软件安装教程1——Neo4j下载与安装

Neo4j的下载地址Neo4j Download Center - Neo4j Graph Data Platform 我下载的是Neo4j社区版&#xff08;免费&#xff09;【企业版收费】 解压后的目录如下&#xff1a; 接下来配置环境变量 进入bin目录&#xff0c;复制路径&#xff1a;E:\neo4j\neo4j-community-5.1.0-win…

决策树——预剪枝和后剪枝

一、 为什么要剪枝 1、未剪枝存在的问题 决策树生成算法递归地产生决策树&#xff0c;直到不能继续下去为止。这样产生的树往往对训练数据的分类很准确&#xff0c;但对未知的测试数据的分类却没有那么准确&#xff0c;即容易出现过拟合现象。解决这个问题的办法是考虑决策树…

【Lua基础 第2章】lua遍历table的方式、运算符、math库、字符串操作方法

文章目录&#x1f4a8;更多相关知识&#x1f447;一、lua遍历table的几种方式&#x1f342;pairs遍历&#x1f342;ipairs遍历&#x1f342;i1,#xxx遍历&#x1f31f;代码演示&#x1f342;pairs 和 ipairs区别二、如何打印出脚本自身的名称三、Lua运算符&#x1f538;算术运算…

微服务治理-含服务线上稳定性保障建设治理

微服务的概念 任何组织在设计一套系统&#xff08;广义概念上的系统&#xff09;时&#xff0c;所交付的设计方案在结构上都与该组织的沟通结构保持一致。 —— 康威定律 微服务是一种研发模式。换句话理解上面这句康威定律&#xff0c;就是说 一旦企业决定采用微服务架构&am…

Js逆向教程-12FuckJs

Js逆向教程-12FuckJs 它利用了js的语法特性&#xff1a; 一、特性1 任何一个js类型的变量结果 加上一个字符串 &#xff0c;只会变成字符串。 数组加上字符串&#xff1a; [0]"" 0true加上字符串 true "" true数字加上字符串 1"" 1二、特性…

14天学习训练营之 初识Pygame

目录 学习知识点 PyGame 之第一个 PyGame 程序 导入模块 初始化 ​​1.screen 2. 游戏业务 学习笔记 当 init () 的时候&#xff0c;它在干什么&#xff1f; init () 实际上检查了哪些东西呢&#xff1f; 它到底 init 了哪些子模块&#xff1f; 总结 14天学习训练营导…

2023年计算机毕设选题推荐

同学们好&#xff0c;这里是海浪学长的毕设系列文章&#xff01; 对毕设有任何疑问都可以问学长哦! 大四是整个大学期间最忙碌的时光,一边要忙着准备考研,考公,考教资或者实习为毕业后面临的就业升学做准备,一边要为毕业设计耗费大量精力。近几年各个学校要求的毕设项目越来越…

·工业 4.0 和第四次工业革命详细介绍

工业 4.0 是制造/生产及相关行业和价值创造过程的数字化转型。 目录 工业 4.0 指南 工业 4.0 与第四次工业革命互换使用&#xff0c;代表了工业价值链组织和控制的新阶段。 网络实体系统构成了工业 4.0 的基础&#xff08;例如&#xff0c;「智慧机器」&#xff09;。他们使用…

基于SpringBoot+Vue的疫苗接种管理系统

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端&#xff1a;SpringBoot 前端&#xff1a;Vue 数据库&#xff1a;MySQL5.7 数据库管理工具&#xff1a;Navicat 12 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / MyEclipse 是否Maven项…

实验二 帧中继协议配置

计算机网络实验实验二 帧中继协议配置一、实验目的二、实验内容三、实验条件四、实验步骤4.1 连接帧中继交换网4.2 创建DLCI4.3 创建串行接口间的虚电路映射关系4.4 配置路由器的串行接口七、思考题实验二 帧中继协议配置 一、实验目的 掌握路由器上配置帧中继协议的方法 掌握…

SSM整合(一)

SSM整合之简单使用通用mapper 1.准备工作 1.1 在java文件夹下面创建所需要的目录 1.2 导入SSM整合时所需要的所有依赖 <properties><!--这个是统一一些spring插件的包名,避免因为版本不一样而报错--><spring.version>5.3.22</spring.version></p…