初识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;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
//重写compareTo方法
    @Override
    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 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;
    }

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


    @Override
    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, "张三");
                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;
    }

    @Override
    public 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> {
    @Override
    public 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;
    }

    @Override
    public 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;
    }

    @Override
    public 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;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
//重写克隆方法
    @Override
    protected 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;
    }

    @Override
    public 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方法
    @Override
    protected 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中的值!

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【C++】list容器

目录 一.list容器介绍 二.C中list的基本组成 三.list容器相关接口的模拟实现 1.push_back() 2.迭代器的begin()和end() 3.insert() 4.erase() 5.pop_front() 6.pop_back() 7.size() 8.empty() 9.析构~list()和清除数据clear() 10.拷贝构造 11.赋值运算 四.模拟…

分享几张漂亮的linux kde主题

分享几张漂亮的linux kde主题&#xff1a;在系统设置的全局主题内下载。

SpringBoot——整合Redis

目录 Redis 创建Commodity表 启动MySQL和Redis 新建一个SpringBoot项目 pom.xml application.properties Commodity实体类 ComMapper接口 ComService业务层接口 ComServiceImpl业务接口的实现类 ComController控制器 RedisConfig配置类 SpringbootRdisApplication启…

c++|多态

c|多态 1 多态的概念2 多态的定义及其实现2.1 满足多态的条件2.2 虚函数2.3 虚函数的重写2.4 析构函数适合加virtural吗2.4 C11 override 和 final2.5 三个概念的对比 3 多态的原理4 抽象类4.1 概念4.2 纯虚函数 1 多态的概念 多态的概念&#xff1a;通俗来说&#xff0c;就是…

微信小程序实现容器图片流式布局功能,配合小程序原生框架使用。

小程序实现容器图片流式布局功能&#xff0c;因为目前论坛上也有很多博主出过类似的文章&#xff0c;这里我就以一个小白角度去讲一下如何实现的吧。给作者一点点鼓励&#xff0c;先点个赞赞吧&#x1f44d;&#xff0c;蟹蟹&#xff01;&#xff01; 目标 实现下方效果图 技术…

HarmonyOS鸿蒙应用开发——安装与配置

今天脑子又抽风&#xff0c;前端转完学后端之后&#xff0c;今天大周末早上醒来突然又想学鸿蒙了&#xff0c;刚好有个比赛需要用到鸿蒙&#xff0c;于是乎我就随便点开b站看了一下鸿蒙视频&#xff0c;然后马上来写这篇博客&#xff0c;后续我的鸿蒙的博客可能会跳着、不连续地…

springboot集成达梦数据库8

springboot集成达梦数据库8 官方文档&#xff1a;[https://eco.dameng.com/document/dm/zh-cn/start/java-development.html](https://eco.dameng.com/document/dm/zh-cn/start/java-development.html) 引入maven依赖 <!--添加数据库驱动安装包--> <dependency> …

十六进制转十进制

十六进制转十进制 在玩编程的时候常会碰到十六进制转换的问题。对于专业的大佬大咖这不是问题&#xff0c;小人物总会有些麻烦。我在研究调色板时也遇到进制转换问题。前些时在本站发了十进制转十六进制的博文&#xff0c;今再写十六进制转十进制的转换方法。供大家参考。 下面…

awk编辑器

目录 工作原理 命令格式 普通格式 BEGIN格式 语句循环格式 awk常见的内建变量&#xff08;可直接用&#xff09; 按行打印行内容 统计行数量 按字段输出文本 通过管道、双引号调用 Shell 命令 awk编辑器是一种流编辑器 工作原理 逐行读取文本,默认以空格或tab键为分…

光环P3O不错的一个讲座

光环P3O不错的一个讲座&#xff0c;地址&#xff1a;https://apphfuydjku5721.h5.xiaoeknow.com/v2/course/alive/l_663dc840e4b0694c62c32d1d?app_idapphfuydJkU5721&share_fromu_5c987304d8515_wH2E5HgCgx&share_type5&share_user_idu_5c987304d8515_wH2E5HgCgx…

AIGC-风格迁移-“DEADiff:稳定可控的文本到图像风格化扩散模型 “-CVPR2024

DEADiff: An Efficient Stylization Diffusion Model with Disentangled Representations 代码&#xff1a;https://tianhao-qi.github.io/DEADiff/ 论文&#xff1a;https://arxiv.org/pdf/2403.06951 本文介绍了一种名为DEADiff的方法&#xff0c;旨在解决基于扩散的文本到图…

又翻车了!谷歌急于手动删除搜索中的奇怪AI答案|TodayAI

谷歌公司近日确认&#xff0c;正在“迅速采取行动”删除一些AI工具的奇怪回应。社交媒体上充斥着谷歌新AI概览产品&#xff08;AI Overview&#xff09;说出奇怪话语的例子&#xff0c;从告诉用户在披萨上涂胶水到建议他们吃石头。这次混乱的AI发布导致谷歌不得不手动禁用某些搜…

车灯合面合壳密封使用UV胶的优缺点是什么呢?汽车车灯的灯罩如果破损破裂破洞了要怎么修复?

车灯合面合壳密封使用UV胶的优缺点是什么呢? 车灯合壳密封使用UV胶的优缺点如下&#xff1a; 优点&#xff1a; 快速固化&#xff1a;UV胶通过紫外线照射可以在短时间内迅速固化&#xff0c;大大缩短了车灯制造的工艺流程时间&#xff0c;提高了生产效率。高度透明&#xff…

二叉树——进阶(递归创建,非递归,广度优先,翻转,深度,对称)

二叉树——进阶 二叉树的递归创建非递归前中后序遍历非递归前序遍历非递归中序遍历非递归后序遍历 广度优先遍历二叉树&#xff08;层序遍历&#xff09;翻转二叉树 二叉树深度最大深度最小深度 对称二叉树 二叉树的递归创建 1&#xff0c;二叉树是一种结构相对固定的数据&…

金融信贷风控系统设计模式应用之模版方法

背景介绍 风控系统每种场景 如个人消费贷 都需要跑很多规则 规则1 申请人姓名身份证号实名验证规则2 申请人手机号码实名认证规则3 银行卡预留手机号码实名认证规则4 申请人银行卡预留手机号码在网状态检验规则5 申请人银行借记卡有效性核验规则6 户籍地址与身份证号归属地比…

微信小程序知识点1

一. 页面样式和结构 1.1 小程序组件(html) (1) 区域布局组件 view 定义块级区域&#xff0c;相当于网页中的 div 标签text 定义行内区域&#xff0c;相当于网页中的 span标签 (2) 链接跳转组件 navigator 组件相当于网页中的 a 标签&#xff0c;用来实现页面之间的跳转。 …

基于卷积神经网络的交通标志识别(pytorch,opencv,yolov5)

文章目录 数据集介绍&#xff1a;resnet18模型代码加载数据集&#xff08;Dataset与Dataloader&#xff09;模型训练训练准确率及损失函数&#xff1a;resnet18交通标志分类源码yolov5检测与识别&#xff08;交通标志&#xff09; 本文共包含两部分&#xff0c; 第一部分是用re…

力扣刷题---2206. 将数组划分成相等数对【简单】

题目描述&#x1f357; 给你一个整数数组 nums &#xff0c;它包含 2 * n 个整数。 你需要将 nums 划分成 n 个数对&#xff0c;满足&#xff1a; 每个元素 只属于一个 数对。 同一数对中的元素 相等 。 如果可以将 nums 划分成 n 个数对&#xff0c;请你返回 true &#xf…

高开高走的续作,可不止《庆余年2》

说起最近霸屏的影视剧&#xff0c;莫过于《庆余年2》。火爆全网的讨论度总归是没有辜负观众们五年的等待&#xff0c;在五月的影视市场独占鳌头已成定局。张若昀、陈道明、李沁等一众演员稳定发挥&#xff0c;剧情节奏随着故事发展渐入佳境&#xff0c;评分一路高涨。 对影视作…

【网络安全】社会工程学攻击与防范

一、社会工程学概述 1、社会工程学的定义 通过利用人们的心理弱点、本能反应、好奇心、信任、贪婪等一些心理陷阱进行的诸如欺骗、伤害、信息盗取、利益谋取等对社会及人类带来危害的行为或方法。 当网络恶意攻击者无法通过纯粹的计算机技术达到目的时&#xff0c;高超的情商…