初识java——javaSE (6)接口的实现——比较器与深拷贝,浅拷贝

文章目录

  • 前言
  • 一 比较器
    • 1.1 关于两个对象的比较
    • 1.2 Comparable接口:
    • 1.3 Arrays.sort方法的实现
    • 1.4 比较器的实现
      • Comparator接口
  • 二 深拷贝与浅拷贝
    • 2.1 浅拷贝:
      • Cloneable接口:
      • clone方法:
      • 实现拷贝:
      • 浅拷贝:
    • 2.2 深拷贝:


前言


上一篇博客并没有将接口的内容阐述完毕,这篇博客继续阐述!

一 比较器

1.1 关于两个对象的比较

在比较单个基本数据类型时,我们可以通过关系运算符进行比较。
 public class Test {public static void main(String[] args) {int age1 = 10;int age2 = 8;System.out.println(age1 > age2);}

在这里插入图片描述

但是当比较对象等引用数据类型时,便不能仅仅通过关系运算符进行比较了。
class Student {String name;int age;public Student(int age, String name) {this.age = age;this.name = name;}}public class Test {public static void main(String[] args) {Student student1 = new Student(10,"张三");Student student2 = new Student(12,"李四");System.out.println(student1>student2);}}

在这里插入图片描述

要进行对象间的比较,需要确定进行比较的规则是什么,比较哪一个属性。

1.2 Comparable接口:

Comparable接口中的compareTo 方法用于进行对象间属性的比较。

在这里插入图片描述
compareTo是一个抽象方法,我们需要重写:

//创建一个Student类,实现Comparable接口
class Student implements Comparable<Student> {String name;int age;public Student(int age, String name) {this.age = age;this.name = name;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}
//重写compareTo方法@Overridepublic int compareTo(Student o) {//比较年龄:if(this.age == o.age){return 0;}else if(this.age>o.age){return 1;}else {return -1;}}//比较姓名//  return this.name.compareTo(o.name);}public class Test {public static void main(String[] args) {Student student1 = new Student(10,"张三");Student student2 = new Student(12,"李四");System.out.println(student1.compareTo(student2));

在这里插入图片描述
结果为-1 ,表明student1的年龄比student2的年龄小。
代码分析:
Student类实现了Comparable接口,
<>是泛型的标记,以后会阐述到,比较那个类,就将类名填写在<>中!

对象间的比较本质上依然是对象属性之间的比较。

1.3 Arrays.sort方法的实现

如果创建一个对象数组,使得数组中的这些对象按照某种规则进行排序
则可以使用Array.sort方法

class Student implements Comparable<Student> {String name;int age;public Student(int age, String name) {this.age = age;this.name = name;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}@Overridepublic int compareTo(Student o) {//比较年龄:if(this.age == o.age){return 0;}else if(this.age>o.age){return 1;}else {return -1;}}//比较姓名//  return this.name.compareTo(o.name);}public class Test {public static void main(String[] args) {Student[] arr1 = new Student[3];arr1[0] = new Student(10, "王五");arr1[1] = new Student(8, "李四");arr1[2] = new Student(9, "张三");Student[] arr1 = {student1,student2,student3};System.out.println("排序前:"+Arrays.toString(arr1));Arrays.sort(arr1);System.out.println("排序后:"+Arrays.toString(arr1));}
}

在这里插入图片描述
排序后,年龄从小到大,依次递增。

如果不实现Comparable接口,会怎么样呢?
在这里插入图片描述
在这里插入图片描述
结果表明Student类型,不能转换成Comparable类型,这是怎么回事,我们调用Arrays.sort方法进行排序,与转换类型有什么关系?

这里我们需要手动实现一下Arrays.sort方法

 public  static  void mysort(Comparable[] comparables){// 用接口数组接收实现接口的数组   采用冒号排序的方式//比较的趟数!for (int i = 0;i<comparables.length-1 ;i++){for (int j = 0; j<comparables.length - 1-i;j++){if(comparables[j].compareTo(comparables[j+1])>0){//如果数组前面元素的值大于数组后面元素的值,则交换引用的值,这是升序Comparable tmp  = comparables[j];comparables[j]  = comparables[j+1];comparables[j+1] = tmp;}}}}

代码分析: 问题就在于 if(comparables[j].compareTo(comparables[j+1])>0) 这条语句
我们通过接口类型数组来接收实现了接口的数组,并且对compareTo方法进行调用!

在上个例子中,因为没有Student没有实现Comparable接口,所以会发生Student类型无法发生向上转型成Comparable接口类型的情况。

调用自己实现的mysort方法:

class Student implements Comparable<Student> {String name;int age;public Student(int age, String name) {this.age = age;this.name = name;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}public int compareTo(Student o) {//比较年龄:if(this.age == o.age){return 0;}else if(this.age>o.age){return 1;}else {return -1;}}//比较姓名//  return this.name.compareTo(o.name);}public class Test {public static void main(String[] args) {Student[] arr1 = new Student[3];arr1[0] = new Student(10, "王五");arr1[1] = new Student(8, "李四");arr1[2] = new Student(9, "张三");System.out.println("排序前:" + Arrays.toString(arr1));mysort(arr1);System.out.println("排序后:" + Arrays.toString(arr1));}}

在这里插入图片描述

1.4 比较器的实现

在上面实现compareTo方法时,我们只能比较某一固定的属性,比如年龄或者名字,
这比较有局限性,总不能当需要比较某一属性时,再去修改类的实现。解决方案:当需要比较某一属性时,就调用相关的类!

Comparator接口

在这里插入图片描述
如图所示:Comparator接口中有一个compare抽象方法。
我们可以创建不同的类来实现此接口,当需要比较不同的属性值时,调用不同的类:

举例:

//在单独一个java文件中
package demo1;import java.util.Comparator;
//创建一个NameComparator类,实现Comparator接口
public class NameComparator implements Comparator<Student> {@Override//实现接口中的抽象方法,用于进行名字之间的比较!public int compare(Student o1, Student o2) {return o1.name.compareTo(o2.name);}
}

o1.name之所以可以引用compareTo方法是因为String类中重写了compareTo方法:
在这里插入图片描述

//在另一个java文件中
package demo1;import java.util.Comparator;
//实现Comparator接口
public class AgeComparator implements Comparator<Student> {@Overridepublic int compare(Student o1, Student o2) {return o1.age - o2.age;}
}
package demo1;import java.util.Arrays;
import java.util.Comparator;//接口的应用!
// 比较两个对象的尝试!
// 实现关于comparable接口!
class Student implements Comparable<Student> {String name;int age;public Student(int age, String name) {this.age = age;this.name = name;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}public int compareTo(Student o) {//比较年龄:if(this.age == o.age){return 0;}else if(this.age>o.age){return 1;}else {return -1;}}//比较姓名//  return this.name.compareTo(o.name);}public class Test {public static void main(String[] args) {Student[] arr1 = new Student[3];arr1[0] = new Student(10, "王五");arr1[1] = new Student(8, "李四");arr1[2] = new Student(9, "张三");System.out.println("排序前:" + Arrays.toString(arr1));//创建一个NameComparator对象。NameComparator nameComparator   =  new NameComparator();//进行名字间的比较!//Arrays.sort方法可以接收第二个参数!Arrays.sort(arr1,nameComparator);System.out.println("排序后:" + Arrays.toString(arr1));}}

这是按照姓名排序的结果:
在这里插入图片描述

按照年龄排序,则调用AgeComparator类:

     System.out.println("排序前:" + Arrays.toString(arr1));AgeComparator ageComparator = new AgeComparator();//根据年龄进行比较!Arrays.sort(arr1,ageComparator);System.out.println("排序后:"+Arrays.toString(arr1));

排序后,年龄从小到大!
在这里插入图片描述

我们通过创建不同的实现Comparator的类,并实现抽象方法compare,
当需要比较某一属性时,即调用某一属性对应类进行比较,这就是比较器的思想与实现!

二 深拷贝与浅拷贝

2.1 浅拷贝:

 所谓拷贝即将一个对象复制一份,由另一个引用指向新复制出的对象。

Cloneable接口:

要进行拷贝的类,需要先实现Cloneable接口.
在这里插入图片描述

Cloneable接口是一个空接口,代表着实现此接口的类可以被拷贝!

clone方法:

clone方法是Object类中用来拷贝对象的方法。
在这里插入图片描述

此方法被Native修饰,说明它是由C/C++等其他编程语言实现,不能查看其具体实现。

实现拷贝:

package demo1;public class Person implements Cloneable{   //实现空接口的类,代表可以拷贝String name;int age ;public Person(String name, int age) {this.name = name;this.age = age;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +'}';}
}
package demo1;
// 浅拷贝public class Test {public static void main(String[] args) {Person person1 = new Person("张三",10);Person person2 =  person1.clone();}
}

(1)此时编译器报警告:
在这里插入图片描述

尽管clone方法的访问权限是protected且Test也是Object的子类,但是当person1调用clone方法时,
是在Person类的外部,所以报错。

解决这个问题,我们需要在子类中重写clone方法:

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

(2) 此时编译器又报警告:

在这里插入图片描述
这是异常的问题,以后会阐述到,解决这个问题,在main方法后,加上一条语句即可:

在这里插入图片描述
(3)编译器又报警告的原因是:
方法的返回值类型为Object类型,我们需要将其强制为Person类型。

package demo1;
// 浅拷贝public class Test {public static void main(String[] args) throws CloneNotSupportedException{Person person1 = new Person("张三",10);Person person2 = (Person) person1.clone();System.out.println(person1);System.out.println(person2);}
}

在这里插入图片描述

此刻,内存中情况如下:
在这里插入图片描述

浅拷贝:

拷贝的情况讲完了,那什么是浅拷贝呢?
当对象中有对象的创建时,此时只拷贝外部的对象,而不拷贝内部的对象,称为浅拷贝!
举例:

package demo1;
//创建一个Person类,实现接口
public class Person implements Cloneable{   //实现空接口的类,代表可以拷贝String name;int age ;Money money1 = new Money(10);public Person(String name, int age) {this.name = name;this.age = age;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +'}';}
//重写克隆方法@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}
}
package demo1;
//创建一个Money类
public class Money {int moneycount ;public Money(int moneycount) {this.moneycount = moneycount;}
}
package demo1;
// 浅拷贝public class Test {public static void main(String[] args) throws CloneNotSupportedException{Person person1 = new Person("张三",10);Person person2 = (Person) person1.clone();System.out.println("修改前:"+person1.money1.moneycount);System.out.println("修改前:"+person2.money1.moneycount);
//仅仅修改person2中的money对象的值,会不会改变person1中的值?person2.money1.moneycount = 20;System.out.println("修改后:"+person1.money1.moneycount);System.out.println("修改后:"+person2.money1.moneycount);}
}

在这里插入图片描述

在内存中情况:
在这里插入图片描述

这种未将对象 中的对象 拷贝的不彻底拷贝,我们称为浅拷贝!

2.2 深拷贝:

深拷贝也就是将对象中的对象也进行拷贝, 
这需要对Person类中的clone方法进行重写:
并且对Money类按照Person类中的格式进行重写编写

代码:

//Person类
package demo1;public class Person implements Cloneable{   //实现空接口的类,代表可以拷贝String name;int age ;Money money1 = new Money(10);public Person(String name, int age) {this.name = name;this.age = age;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +'}';}@Override//重写后的方法protected Object clone() throws CloneNotSupportedException {Person tmp = (Person) super.clone();    //谁调用了super方法,不需要this指定对象。//对于对象中的对象也进行拷贝!tmp.money1 = (Money) this.money1.clone();return tmp;}
}
//Money类
package demo1;public class Money implements Cloneable {int moneycount ;public Money(int moneycount) {this.moneycount = moneycount;}
//也重写clone方法@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}
}
//测试类
package demo1;
// 浅拷贝public class Test {public static void main(String[] args) throws CloneNotSupportedException{Person person1 = new Person("张三",10);Person person2 = (Person) person1.clone();System.out.println("修改前:"+person1.money1.moneycount);System.out.println("修改前:"+person2.money1.moneycount);person2.money1.moneycount = 20;System.out.println("修改后:"+person1.money1.moneycount);System.out.println("修改后:"+person2.money1.moneycount);}

在这里插入图片描述
结果表明,此时深拷贝成功,修改person2中的money值,不会改变person1中的值!

在内存中的展示:
在这里插入图片描述

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

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

相关文章

Python3 笔记:Python的所有关键字

查看Python的关键字首先需要用import导入keyword模块 import keyword # 查看Python的所有关键字&#xff0c;先用import导入keyword模块 print(keyword.kwlist) 运行结果&#xff1a; [False, None, True, and, as, assert, async, await, break, class, continue, def, …

ASP+ACCESS基于WEB网上留言板

摘要 本文概述了ACCESS数据库及其相关的一些知识&#xff0c;着重论述ACCESS数据库和ASP的中间技术&#xff0c;构建一个简单的留言板。具体的实现是构造一个留言板系统&#xff0c;能很方便的和同学沟通和交流。留言板具有功能强大、使用方便的特点。用户以个人的身份进入&am…

瑞芯微RV1126——人脸识别源码分析

本节内容主要分为3部分&#xff0c;第一部分是流程结构图;第二部分为人脸识别代码流程;第三部分为具体的代码分析。 1.流程结构图 2.人脸识别代码流程 1、人脸数据的初始化&#xff1a; init_all_rockx_face_data();init_face_data();2、创建rtsp会话&#xff0c;这里包括发…

一个典型的分布式缓存系统是什么样的?no.32

分布式 Redis 服务 由于本课程聚焦于缓存&#xff0c;接下来&#xff0c;我将以微博内的 分布式 Redis 服务系统为例&#xff0c;介绍一个典型的分布式缓存系统的组成。 微博的 Redis 服务内部也称为 RedisService。RedisService 的整体架构如图所示。主要分为Proxy、存储、集…

产品推荐 | 基于Xilinx XCKU115的半高PCIe x8 硬件加速卡

一、板卡概述 本板卡系我公司自主研发&#xff0c;采用Xilinx公司的XCKU115-3-FLVF1924-E芯片作为主处理器&#xff0c;主要用于FPGA硬件加速。板卡设计满足工业级要求。如下图所示&#xff1a; 二、功能和技术指标 板卡功能 参数内容 主处理器 XCKU115-3-FLVF1924-E 板卡…

UE4/UE5像素流送云推流:多人访问不稳定、画面糊、端口占用多等

UE4/UE5想要实现网页访问&#xff0c;很多工程师会选择guan方的像素流送。但这个技术要求在模型开发初期就接入。对于一些已有UE模型是无法进行流化的。虽然也可以解决新UE模型的网页访问问题&#xff0c;但在实际的应用中&#xff0c;点量云流也收到很多反馈说&#xff0c;使用…

Python爬取B站视频:封装一下

&#x1f4da;博客主页&#xff1a;knighthood2001 ✨公众号&#xff1a;认知up吧 &#xff08;目前正在带领大家一起提升认知&#xff0c;感兴趣可以来围观一下&#xff09; &#x1f383;知识星球&#xff1a;【认知up吧|成长|副业】介绍 ❤️如遇文章付费&#xff0c;可先看…

大数据Hadoop之-工具HIVE(一)

大数据Hadoop之——数据仓库Hive HIVE介绍Hive是基于Hadoop的一个数据仓库(Data Aarehouse,简称数仓、DW),可以将结构化的数据文件映射为一张数据库表,并提供类SQL查询功能。是用于存储、分析、报告的数据系统。 在Hadoop生态系统中,HDFS用于存储数据,Yarn用于资源管理…

【Linux】中的常见的重要指令(中)

目录 一、man指令 二、cp指令 三、cat指令 四、mv指令 五、more指令 六、less指令 七、head指令 八、tail指令 一、man指令 Linux的命令有很多参数&#xff0c;我们不可能全记住&#xff0c;我们可以通过查看联机手册获取帮助。访问Linux手册页的命令是 man 语法: m…

白嫖免费图床!CloudFlare R2太香了!

1 为啥要折腾搭建一个专属图床&#xff1f; 技术大佬写博客都用 md 格式&#xff0c;要在多平台发布&#xff0c;图片就得有外链后续如博客迁移&#xff0c;国内博客网站如掘金&#xff0c;简书&#xff0c;语雀等都做了防盗链&#xff0c;图片无法迁移 2 为啥选择CloudFlare…

对话太医管家CEO徐晶:数字化技术正在为健康管理行业带来新平衡丨数字思考者50人...

ITValue 钛媒体特别专题策划《数字思考者50人》&#xff1a;探访中国深刻的数字化思考者群体。我们理解的“TechThinker”&#xff0c;涵盖了中国数字化浪潮中的技术践行者、政策制定者与投资决策者。在这场长达10年的乘风破浪中&#xff0c;每个人都在分享技术进步的果实&…

文件系统--软硬链接

文章目录 现象软链接硬链接 现象 建立软链接 建立硬链接 // 删除软硬链接都可以用 unlink 指令 unlink soft-link软链接 软链接是一个独立的文件&#xff0c;因为有独立的inode number 软链接的内容&#xff1a;目标文件所对应的路劲字符串如果我们直接查看软链接文件&#…

vue2vue3为什么el-table树状表格失效?

上图所示&#xff0c;后端返回字段中有hasChildren字段。 解决树状表格失效方案&#xff1a; 从后端拿到数据后&#xff0c;递归去掉该字段&#xff0c;然后就能正常显示。&#xff08;复制下方代码&#xff0c;直接用&#xff09; 亲测有效&#xff0c;vue2、vue3通用 /**…

如何运用多媒体,打造企业实力展示厅?

企业文化、产品是其长期发展的根本所在&#xff0c;为此越来越多的企业开始选择运用多媒体互动&#xff0c;来打造企业多媒体展厅的方式&#xff0c;对企业文化、品牌形象、产品进行推广宣传&#xff0c;并在多媒体互动装置的支持下&#xff0c;能让客户能够快速且全面的了解企…

基于SSM的“酒店管理系统”的设计与实现(源码+数据库+文档)

基于SSM的“酒店管理系统”的设计与实现&#xff08;源码数据库文档) 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SSM 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 首页 管理员登录页面 用户管理页面 客房信息查询 酒店详细信息 后台…

APP广告变现怎么实现的,背后逻辑是什么?

广告变现的实现主要基于以下几个关键步骤和逻辑&#xff1a; 用户获取与留存&#xff1a;首先&#xff0c;APP需要吸引足够的用户并确保他们的留存率。只有拥有庞大且活跃的用户基础&#xff0c;APP才能吸引广告商投放广告。因此&#xff0c;开发者需要通过优化APP质量、提升用…

数字人实训室解决方案

前言 近年来&#xff0c;政策层面的积极推动为数字人产业铺设了坚实的基石。2021年&#xff0c;“十四五”规划将虚拟数字技术纳入其中&#xff0c;强调技术创新引领行业应用的革新&#xff0c;加速数字人在各领域的实际应用。紧接着的《“十四五”数字经济发展规划》进一步明确…

Nodejs 第七十三章(网关层)

什么是网关层(getway)&#xff1f; 技术选型fastify 速度快适合网关层 fastify教程上一章有讲 网关层是位于客户端和后端服务之间的中间层&#xff0c;用于处理和转发请求。它充当了请求的入口点&#xff0c;并负责将请求路由到适当的后端服务&#xff0c;并将后端服务的响应…

一个基于HOOK机制的微信机器人

一个基于✨HOOK机制的微信机器人&#xff0c;支持&#x1f331;安全新闻定时推送【FreeBuf&#xff0c;先知&#xff0c;安全客&#xff0c;奇安信攻防社区】&#xff0c;&#x1f46f;Kfc文案&#xff0c;⚡备案查询&#xff0c;⚡手机号归属地查询&#xff0c;⚡WHOIS信息查询…

有哪些地图采集软件可以采集商家数据导出功能?

1.国内商家采集 寅甲地图数据采集软件 寅甲地图数据采集软件一款多关键词多城市同时采集百度地图、360地图、高德地图、搜狗地图、腾讯地图、图吧地图、天地图商家、公司、店铺的手机、座机、地址、坐标等数据信息的软件。 2.国外商家采集 寅甲谷歌地图数据采集软件 专为做…