Comparable+Comparator+Cloneable接口

news2024/12/26 3:43:13

文章目录

  • Comparable
  • Comparator
  • Cloneable
    • 浅拷贝
    • 深拷贝


Comparable

当我们需要对一个自己写的类进行排序(Collections.sortArrays.sort)的时候,,就要使用到Comparable接口。

该接口中有一个compareTo方法,该方法其实就是一比较规则。

public interface Comparable<T> {
    public int compareTo(T o);
}

然后比较当前对象和参数对象的大小关系(按分数来算).

  • 如果当前对象应排在参数对象之前, 返回小于 0 的数字;
  • 如果当前对象应排在参数对象之后, 返回大于 0 的数字;
  • 如果当前对象和参数对象不分先后, 返回 0

所以如果自己的类需要进行排序的时候,就需要实现Comparable该接口,并重写compareTo方法,该法就可以通过指定字段进行排序,比如年龄。

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

class Student implements Comparable<Student> {
    int id;
    String name;
    int age;

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

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
    // 谁调用的compareTo,谁就是this
    @Override
    public int compareTo(Student o) {
        return this.age -o.age;
    }
}
public class TestDemo {
    public static void main(String[] args) {
        List<Student> students = new ArrayList<>();
        students.add(new Student(2,"张三",20));
        students.add(new Student(3,"李四",18));
        students.add(new Student(1,"王五",15));

        System.out.println(students);
        Collections.sort(students);
        System.out.println(students);
    }
}

运行结果

[Student{id=2, name='张三', age=20}, Student{id=3, name='李四', age=18}, Student{id=1, name='王五', age=15}]
[Student{id=1, name='王五', age=15}, Student{id=3, name='李四', age=18}, Student{id=2, name='张三', age=20}]

该接口对类的侵入性比较强,但是如果这个比较规则已经被很多人使用,你突然想换个比较规则,如果修改比较规则必然会造成损失,所以这个方方法对类的侵入性太强了,并不是特别好。

Comparator

刚刚我们说 Comparable 对类的侵入性太强了,但有另外一个接口它十分灵活。就是Comparator

代码示例:

我们写了两个类,分别实现了 Comparator 这个接口,一个是用年龄比较,一个是用姓名比较。我们叫做比较器.

import java.util.Comparator;

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

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

再来看原来的代码,我们的Student并没有实现任何接口,也没有重写compareTo 方法。
只是实例化了刚刚上面两个比较器,在用sort排序时,传过去了两个参数,一个是要排序的集合,一个是我们写的比较器对象。

class Student{
    int id;
    String name;
    int age;

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

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
public class TestDemo {
    public static void main(String[] args) {
        List<Student> students = new ArrayList<>();
        students.add(new Student(3,"李四",18));
        students.add(new Student(1,"王五",15));
        students.add(new Student(2,"张三",20));

        System.out.println(students);
        //按姓名排序
        NameComparator nameComparator = new NameComparator();
        Collections.sort(students,nameComparator);
        System.out.println(students);
        // 按年龄排序
        AgeComparator ageComparator = new AgeComparator();
        Collections.sort(students,ageComparator);
        System.out.println(students);

    }
}

运行结果

[Student{id=3, name='李四', age=18}, Student{id=1, name='王五', age=15}, Student{id=2, name='张三', age=20}]
[Student{id=2, name='张三', age=20}, Student{id=3, name='李四', age=18}, Student{id=1, name='王五', age=15}]
[Student{id=1, name='王五', age=15}, Student{id=3, name='李四', age=18}, Student{id=2, name='张三', age=20}]

Comparator 接口,如果要进行比较只需要根据自己的需要写一个比较器就好了,并不像第一个接口那样直接写死了。

Cloneable

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

  • 实现Clonable接口
  • 记住要处理异常
  • 重写 Object 的 clone 方法
class Person implements Cloneable {
    String name;
    int age;

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

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

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
public class CloneableDemo {
    public static void main(String[] args) throws CloneNotSupportedException {
        Person std1 = new Person("张三",18);
        Person std2 = (Person) p1.clone();
        System.out.println(std1);
        System.out.println(std2);

    }
}

运行结果

Person{name='张三', age=18}
Person{name='张三', age=18}

此时的内存布局

在这里插入图片描述

如果一个类里的成员变量是另外一个类,使用clone对其进行拷贝

浅拷贝

class Test {
    int val;
    public Test(int val) {
        this.val = val;
    }

    @Override
    public String toString() {
        return "Test{" +
                "val=" + val +
                '}';
    }
}
class Person implements Cloneable {
    String name;
    int age;
    Test t;
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

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

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
public class CloneableDemo {
    public static void main(String[] args) throws CloneNotSupportedException {
        Person std1 = new Person("张三",18);
        std1.t = new Test(100);
        Person std2 = (Person) p1.clone();
        std2.t.val = 200;
        System.out.println(std1);
        System.out.println(std2);

    }
}

运行结果

Person{name='张三', age=18, t=Test{val=200}}
Person{name='张三', age=18, t=Test{val=200}}

当我们对拷贝后的对象也就是p2里的Test示例进行修改时,p1也发生了改变。此时就是一个典型的浅拷贝

此时的内存布局,这个拷贝就是将一个对象原样克隆了一份,它其时两个对象里的Test示例对象还是指向的同一个 对象

在这里插入图片描述

深拷贝

要想实现深拷贝,就得修改clone方法,再让其包含的Test类也要实现Cloneable接口重写clone接口,让Person对象在拷贝的同时把Test示例也给拷贝,这样就实现深拷贝。

class Test implements Cloneable {
    int val;
    public Test(int val) {
        this.val = val;
    }

    @Override
    public String toString() {
        return "Test{" +
                "val=" + val +
                '}';
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
class Person implements Cloneable {
    String name;
    int age;
    Test t;
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

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

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Person person = (Person) super.clone();
        person.t = (Test) this.t.clone();

        return person;
    }
}
public class CloneableDemo {
    public static void main(String[] args) throws CloneNotSupportedException {
        Person p1 = new Person("张三",18);
        p1.t = new Test(100);
        Person p2 = (Person) p1.clone();
        p2.t.val = 200;
        System.out.println(p1);
        System.out.println(p2);

    }
}

运行结果

Person{name='张三', age=18, t=Test{val=100}}
Person{name='张三', age=18, t=Test{val=200}}

此时的内存布局

在这里插入图片描述


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

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

相关文章

货币银行学

建立大脑知识库 外汇储备不宜太高&#xff0c;2022年是3万亿。 美元贬值&#xff0c;大宗商品会更贵。 大宗商品 [1] &#xff08;Commodities&#xff09;是指可进入流通领域&#xff0c;但非零售环节&#xff0c;具有商品属性并用于工农业生产与消费使用的大批量买卖的物质商…

Oracle Id生成算法 —— 雪花算法

背景 近几日&#xff0c;被主键ID生成折磨的不太行&#xff0c;于是就在寻找一种合适的主键生成策略&#xff0c;选择一种合适的主键生成策略&#xff0c;可以大大降低主键ID的维护成本。 主键ID生成方法 最常用的4种主键ID生成方法 UUID&#xff1a;全局唯一性&#xff0c…

【框架】Spring

1、IOC 1、自动化配置 xml文件 注册bean 属性注入&#xff1a;setter&#xff0c;构造方法&#xff0c;p命名空间&#xff0c;外部注入 复杂属性&#xff1a;对象ref&#xff0c;数组array&#xff0c;list&#xff0c;map 依赖注入&#xff1a;ctx.getBean()Java配置类 Conf…

InterruptedException异常解析

Either re-interrupt this method or rethrow the “InterruptedException”. 请重新中断此方法或重新引发“InterruptedException”。 文章目录问题描述问题解析sonar检测提示规则解决方案问题描述 public void run () {try {while (true) {// do stuff}}catch (InterruptedE…

webgl变换矩阵理论详解

文章目录前言矩阵运算矩阵加减矩阵数乘矩阵乘矩阵矩阵转置逆矩阵正交矩阵矩阵变换的一般规则行主序和列主序行向量和列向量复杂变换时的顺序变换矩阵进行图形变换uniform传递矩阵平移缩放旋转组合变换实例总结前言 在webgl中将图形进行平移、旋转、缩放等操作时可以在着色器中…

11.1 使用关联容器

文章目录关联容器的类型使用map使用set关联容器中元素是按关键字保存和访问的&#xff0c;支持高效关键字查找和访问。顺序容器中元素是按他们在容器中的位置保存访问的。关联容器有两个主要类型&#xff1a;set和map。 set&#xff1a;每个元素包含一个关键字&#xff0c;想知…

OPC实践:通过 python-docx 读取 docx 文档

概述 本文记录下列命令执行的过程&#xff0c;通过对过程中的关键步骤进行记录&#xff0c;掌握 python-docx 库中 opc 与 parts 模块的源码、以及加深对 OPC 的理解。 import docx# fp 为 docx 文件路径&#xff0c; docx 包含一个 hello 字符串、一张 jepg 图片及一个表格…

<Python的列表和元组>——《Python》

目录 1.列表 1.1 列表的概念 1.2 创建列表 1.3 访问下标 1.4 切片操作 1.5 遍历列表元素 1.6 新增元素 1.7 查找元素 1.8 删除元素 1.9 连接列表 2. 元组 1.列表 1.1 列表的概念 编程中, 经常需要使用变量, 来保存/表示数据. 如果代码中需要表示的数据个数比较少,…

初识 Bootstrap(前端开发框架)

初识 Bootstrap&#xff08;前端开发框架&#xff09;参考Bootstrap特点获取目录结构jQuery 与 Popper准备工作包含 jQuery 与 Poppermetabox-sizing基本模板无注释版本注释版本参考 项目描述Bootstrap 官方教程https://getbootstrap.net/docs/getting-started/introduction/百…

字节青训前端笔记 | HTTP 使用指南

本节课介绍 Http 协议的基本定义和特点&#xff0c;在此基础上&#xff0c;对于 Http 协议的发展历程及报文结构展开进一步分析。 从输入字符串到打开网页 输入地址浏览器处理输入信息浏览器发请求到达服务器服务器返回信息浏览器读取响应信息浏览器渲染页面加载完成 什么是…

KVM虚拟化简介 | 初识

目录 1、kvm架构 2、架构解析 3、kvm和qemu的作用 1、kvm架构 2、架构解析 从rhel6开始使用&#xff0c;红帽公司直接把KVM的模块做成了内核的一部分。xen用在rhel6之前的企业版中默认内核不支持&#xff0c;需要重新安装带xen功能的内核KVM 针对运行在x86 硬件上的、驻留在内…

配置 Git 连接 GitHub

文章目录0.安装 Git1.注册 GitHub 账号2.配置 Git 的用户名和邮箱3.为本机生成 SSH 密钥对4.将公钥拷贝到 GitHub 上5.测试0.安装 Git Git 官网链接&#xff1a;https://git-scm.com/ Git 官网下载链接&#xff1a;https://git-scm.com/downloads 1.注册 GitHub 账号 GitHu…

蓝桥杯STM32G431RBT6学习——定时器PWM输出

蓝桥杯STM32G431RBT6学习——定时器PWM输出 前言 PWM波输出作为定时器的一个常用功能&#xff0c;也属于高频的考点。从数据手册的定时器解析可以了解到&#xff08;上篇描述&#xff09;&#xff1a;除了基本定时器&#xff08;TIM6、7&#xff09;外&#xff0c;其他所有定…

全国产网管型工业交换机的几种管理方式

全国产网管型工业交换机按其字面上的意思&#xff0c;一是全国产化&#xff08;工业交换机&#xff09;&#xff0c;就是交换机内部95%以上元器件的国内生产制造&#xff0c;重要的硬件芯片&#xff0c;比如交换机芯片、管理芯片、接口芯片等必须是国内厂商在国内研发、生产、制…

学习记录664@项目管理之项目进度管理

什么是项目进度管理 项目进度管理包括为管理项目按时完成所需的7个过程&#xff0c;具体为: 规划进度管理过程一一制定政策、程序和文档以管理项目进度。定义活动过程一一识别和记录为完成项目可交付成果而需采取的具体行动。排列活动顺序过程一一识别和记录项目活动之间的关…

【Kubernetes 企业项目实战】04、基于 K8s 构建 EFK+logstash+kafka 日志平台(下)

目录 一、安装收集日志组件 Fluentd 二、kibana 可视化展示查询 k8s 容器日志 三、测试 efk 收集生产环境业务 pod 日志 四、基于 EFKlogstashkafka 构建高吞吐量的日志平台 4.1 部署 fluentd 4.2 接入 kafka 4.3 配置 logstash 4.4 启动 logstash 本篇文章所用到的资料…

对象的比较

Java中基本类型间的元素比较&#xff0c;可以直接通过">"、"<"、""等符号判断大小&#xff0c;也可使用compareTo比较大小或者equals判断是否相等&#xff0c;作为引用类型的String类不可以使用">"、"<"比较大小…

2023最新 - 谷歌学术文献Bibtex批量获取脚本

首先&#xff0c;自行解决网络访问问题&#xff0c;保证能访问到谷歌学术&#xff0c;否则下面可免看 第一步&#xff1a;安装 selenium python 安装 selenium pip install selenium 第二步&#xff1a;安装 Chrome 浏览器 http://chorm.com.cn/ 第三步&#xff1a;根据 …

Linux应用基础——控制服务与守护进程

一、systemd基本介绍 1.作用 systemd守护进程管理Linux的启动&#xff0c;一般包括服务启动和服务管理&#xff0c;它可以在系统引导时以及运行中的系统上激活系统资源、服务器守护进程和其他进程 2.守护进程 守护进程是执行各种任务的后台等待或运行的进程&#xff0c;一般…

day18|235. 二叉搜索树的最近公共祖先、701.二叉搜索树中的插入操作、450.删除二叉搜索树中的节点

235. 二叉搜索树的最近公共祖先 给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。 最近公共祖先的定义为&#xff1a;“对于有根树 T 的两个结点 p、q&#xff0c;最近公共祖先表示为一个结点 x&#xff0c;满足 x 是 p、q 的祖先且 x 的深度尽可能大&#xff08…