Java语言-接口(下)

目录

1. 接口使用实例

1.1 给对象数组排序

1.2  Clonable接口和深拷贝

Cloneable

浅拷贝

深拷贝

1.3 抽象类和接口的区别

2. Object类

2.1 Object类的介绍

2.2 toString()

2.3 equals()

2.4 hashcode()



1. 接口使用实例

1.1 给对象数组排序

现有一个学生类:

class Student{private String name;private int score;public Student(String name, int score) {this.name = name;this.score = score;}@Overridepublic String toString() {return "["+this.name+":"+this.score+"]";}
}
再给定一个学生对象数组 , 对这个对象数组中的元素进行排序 ( 按分数降序 ).
public static void main(String[] args) {Student[] students={new Student("zhangsan",95),new Student("lisi",92),new Student("wangwu",97),new Student("zhaoliu",90)};
}

在数组类 Arrays 里,我们有一个现成的方法 sort ,比如以下案例:

        int[] arr={1,3,2,4,6,5,9,8,7};Arrays.sort(arr);System.out.println(Arrays.toString(arr));

对于学生类Student组成的数组,不能直接使用这个方法:

原因:两个整数是可以进行比较的,但是两个学生对象的大小关系无法直接确定...

让我们的 Student 类实现 Comparable 接口 , 并实现其中的 compareTo 方法
sort 方法中会自动调用 compareTo 方法
然后比较当前对象和参数对象的大小关系 ( 按分数来算 ).
如果当前对象应排在参数对象之前 , 返回小于 0 的数字 ;
如果当前对象应排在参数对象之后 , 返回大于 0 的数字 ;
如果当前对象和参数对象不分先后 , 返回 0;
再次执行程序 , 结果就符合预期了 .

为了进一步加深对接口的理解 , 我们可以尝试自己实现一个 sort 方法来完成刚才的排序过程
(使用冒泡排序)
public static void sort(Comparable array[]){for (int bound = 0; bound < array.length; bound++) {for (int cur = array.length-1; cur > bound; cur--) {if(array[cur-1].compareTo(array[cur])>0){Comparable tmp=array[cur];array[cur]=array[cur-1];array[cur-1]=tmp;}}}}
再次执行代码
        sort(students);System.out.println(Arrays.toString(students));

如果我们不想要按照分数的高低来排序,而是按照名字来排序,应该如何写?

重写compareTo方法如下:

    @Overridepublic int compareTo(Student o) {return this.name.compareTo(o.name);}

然而,这种写法有一个明显的缺陷:

不适合灵活的比较,只适合用于固定的比较。

比如,想要从按照分数比较换成按名字比较,就需要重新写一个compareTo方法,使用起来不方便...

解决方法:换一个接口。(使用 Comparator 接口)

另外写两个类,实现Comparator接口,分别实现按名字比较和按分数比较的功能:

class ScoreComparator implements Comparator<Student>{@Overridepublic int compare(Student o1, Student o2) {return o1.getScore()-o2.getScore();}
}class NameComparator implements Comparator<Student>{@Overridepublic int compare(Student o1, Student o2) {return o1.getName().compareTo(o2.getName());}
}

然后将以上两个类分别实例化,用哪个类作为参数传入Arrays.sort中,就按哪种方式比较:

        //实例化两个类ScoreComparator scoreComparator=new ScoreComparator();NameComparator nameComparator=new NameComparator();//按照分数比较Arrays.sort(students,scoreComparator);System.out.println(Arrays.toString(students));//按照名字比较Arrays.sort(students,nameComparator);System.out.println(Arrays.toString(students));

1.2  Clonable接口和深拷贝

Cloneable

Java 中内置了一些很有用的接口 , Clonable 就是其中之一 .
Object 类中存在一个 clone 方法 , 调用这个方法可以创建一个对象的 " 拷贝 ". 但是要想合法调用 clone 方法 , 必须要先实现 Clonable 接口 , 否则就会抛出 CloneNotSupportedException 异常 .

案例:

class Animal implements Cloneable{private String name;private int age;public Animal(String name, int age) {this.name = name;this.age = age;}@Overridepublic String toString() {return "Animal{" +"name='" + name + '\'' +", age=" + age +'}';}@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}
}
public class Demo3 {public static void main(String[] args) throws CloneNotSupportedException {Animal animal1=new Animal("小财",3);Animal animal2=(Animal) animal1.clone();System.out.println(animal1);System.out.println(animal2);}
}

【注意事项】

1.要调用对象的clone()方法,首先要在类里面重写clone()方法。

2.clone方法要抛出CloneNotSupportedException异常,否则编译器会报错。

3.clone()方法的返回值是Object类型,需要向下转型才能接收。

4.类要实现Cloneable接口,否则运行编译器会抛出 CloneNotSupportedException异常.

克隆过程图解:


增加一个类Money,并且该类实例化对象作为类Person的成员变量:

class Money{public double val=9.9;
}
class Person implements Cloneable{private String name;private int age;public Money money=new Money();public Person(String name, int age) {this.name = name;this.age = age;}@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}
}

浅拷贝

案例:

public class Demo3 {public static void main(String[] args) throws CloneNotSupportedException {Person p1= new Person("zhangsan",10);Person p2= (Person) p1.clone();System.out.println("修改前:"+p1.money.val);System.out.println("修改前:"+p2.money.val);p1.money.val=99;System.out.println("修改后:"+p1.money.val);System.out.println("修改后:"+p1.money.val);}
}

运行结果:

可以看到:改变p1的成员money后,p2的成员money也跟着改变了——这就是潜拷贝。

分析原因:

原因:money是一个引用变量,可以理解为p1的引用变量money里面储存了对象new Money()的地址,而克隆出来的p2的引用变量跟p1的引用变量储存了同一个地址,因此修改p1的money,p2的money也会改变。


深拷贝

更改Person类里的重写方法,将克隆出来的新对象的引用变量成员money指向另一个对象(不是跟p1的对象同一个):

    @Overrideprotected Object clone() throws CloneNotSupportedException {Person tmp=(Person) super.clone();//tmp.money=new Money();//写法1tmp.money=(Money) this.money.clone();//写法2return tmp;}

再次运行的结果:

1.3 抽象类和接口的区别

核心区别 : 抽象类中可以包含普通方法和普通字段 , 这样的普通方法和字段可以被子类直接使用 ( 不必重写 ), 而接口中不能包含普通方法, 子类必须重写所有的抽象方法 .
【注意】
抽象类存在的意义是为了让编译器更好的校验, 像 Animal 这样的类我们并不会直接使用, 而是使用它的子类.
万一不小心创建了 Animal 的实例, 编译器会及时提醒我们.
      No        区别       抽象类(abstract)                  接口(interface)
      1结构组成普通类+抽象方法抽象方法+全局变量
      2权限各种权限public
      3子类使用使用extends关键字继承抽象类使用implements关键字实现接口
     4关系一个抽象类可以实现若干个接口接口不能继承抽象类,但是接口可以使用extends关键字继承多个父接口
     5子类限制一个子类只能继承一个抽象类一个子类可以实现多个接口

2. Object类

2.1 Object类的介绍

Object Java 默认提供的一个类。 Java 里面除了 Object 类,所有的类都是存在继承关系的。 默认会继承Object父类 。即所有类的对象都可以使用Object 的引用进行接收。
范例:使用 Object 接收所有类的对象
class Animal {
}
class Person{
}
public class Demo3 {public static void function(Object o){System.out.println(o);
}public static void main(String[] args) {function(new Animal());function(new Person());}
}

Object类中包含了很多方法。

本次学习中,我们主要学习这几个方法:toString()方法,equals()方法,hashcode()方法

2.2 toString()

Animal类默认继承Object类,重写toString方法如下:

class Animal {private String name;private int age;public Animal(String name, int age) {this.name = name;this.age = age;}@Overridepublic String toString() {return "Animal{" +"name='" + name + '\'' +", age=" + age +'}';}
}
public class Demo3 {public static void main(String[] args) {System.out.println(new Animal("旺财",3));}
}

2.3 equals()

Java 中, == 进行比较时:
a. 如果 == 左右两侧是基本类型变量,比较的是变量中值是否相同
b. 如果 == 左右两侧是引用类型变量,比较的是引用变量地址是否相同
c. 如果要比较对象中内容,必须重写Object中的equals方法,因为equals 方法默认也是按照地址比较的:
// Object 类中的 equals 方法
public boolean equals ( Object obj ) {
return ( this == obj ); // 使用引用中的地址直接来进行比较
}

使用案例:

没有重写equals方法如下:

class Person{private String name;private int age;public Person(String name, int age) {this.name = name;this.age = age;}
}
public class Demo3 {public static void main(String[] args) {Person p1=new Person("张三",18);Person p2=new Person("张三",18);System.out.println(p1.equals(p2));}
}

重写了equals方法如下:

class Person{private String name;private int age;public Person(String name, int age) {this.name = name;this.age = age;}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null ) return false;//不是Person类if(!(o instanceof Person)) return false;Person person = (Person) o;return this.age == person.age && this.name.equals(person.name);}}

结论:比较对象中内容是否相同的时候,一定要重写 equals 方法。

2.4 hashcode()

    public static void main(String[] args) {Person p1=new Person("张三",18);Person p2=new Person("张三",18);System.out.println(p1.hashCode());System.out.println(p2.hashCode());}
调用hashCode() 这个方法,他会帮我算一个具体的 对象位置。
我们认为两个名字相同,年龄相同的对象,将存储在同一个位置,如果不重写 hashcode() 方法,
算出来的位置(hash值)就会不一样

如果要使算出来的位置一样,就需要重写 hashcode() 方法:

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

对象p1和p2的name和age都相同,那么将name和age作为条件传入hash方法中,算出来的hash值就是一致的:


如果哪里有疑问的话欢迎来评论区指出和讨论,如果觉得文章有价值的话就请给我点个关注还有免费的收藏和赞吧,谢谢大家!

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

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

相关文章

关于java继承(深入解析父类属性的抽取与构造函数的作用)

目录 前言基础继承作用 理论分析父类属性的抽取构造函数调用父类构造函数会不会创建一个父类的对象&#xff1f;生命周期角度谁的属性用谁的构造函数初始化 示例解析代码代码调试展示构造函数初始化成员变量 总结 前言 在Java中&#xff0c;继承是一项至关重要的特性&#xff0…

详解23种设计模式——第二部分:结构型模式

目录 3 结构型模式 3.1 代理模式 3.2 适配器模式 3.2.1 默认适配器模式 3.2.2 对象适配器模式 3.2.3 类适配器模式 3.2.4 适配器模式总结 3.3 桥梁模式 3.4 装饰模式 3.4 门面模式 3.5 组合模式 3.6 享元模式 3.7 结构型模式总结 接上一篇&#xff1a;详解23种设计…

openrtp 音视频时间戳问题

解决音视频发送的rtp问题 openrtp增加了音频aac的发送&#xff0c;地址 OpenRTP Gitee开源地址 同时使用两个rtp &#xff0c;来发送音频和视频 使用以下音频rtp&#xff0c;是可以发送和接收的&#xff0c;音频端口在视频端口上2 v0 o- 0 0 IN IP4 127.0.0.1 sMy Stream cI…

Windows通过netsh控制安全中心防火墙和网络保护策略

Windows通过netsh控制安全中心防火墙和网络保护策略 1. 工具简介 【1】. Windows安全中心 【2】. netsh工具 netsh(Network Shell) 是一个Windows系统本身提供的功能强大的网络配置命令行工具。 2. 开启/关闭防火墙策略 在设置端口&#xff08;禁用/启用&#xff09;前&am…

使用 CDN 后 Apache 的日志记录客户真实 IP

经常搭建网站服务器的都知道&#xff0c;在给站点使用了 CDN 后 Web 应用的日志记录里就会只记录 CDN 节点 IP 了&#xff0c;这就没法看到真实客户请求 IP&#xff0c;对于日志分析、运维日常维护来说就有点儿麻烦了&#xff0c;今天明月结合在五洛云服务器上搭建的Apache环境…

多ip访问多网站

多IP访问多网站 1.预配操作 [rootlocalhost ~]# mount /dev/sr0 /mnt mount: /mnt: WARNING: source write-protected, mounted read-only. [rootlocalhost ~]# systemctl stop firewalld ----------关闭防火墙 [rootlocalhost ~]# setenforce 0 -------关闭selinux2.安装n…

【论文阅读】ESRGAN

学习资料 论文题目:增强型超分辨率生成对抗网络(ESRGAN: Enhanced Super-Resolution Generative Adversarial Networks)论文地址:[1809.00219] ESRGAN:增强型超分辨率生成对抗网络代码:xinntao / ESRGAN:ECCV18 研讨会 - 增强的 SRGAN。Champion PIRM Challenge 关于感知…

【机器学习】VQ-VAE(Vector Quantized Variational Autoencoder)

VQ-VAE&#xff08;Vector Quantized Variational Autoencoder&#xff09;是一种生成模型&#xff0c;它结合了变分自编码器&#xff08;Variational Autoencoder, VAE&#xff09;和向量量化&#xff08;Vector Quantization&#xff09;技术。VQ-VAE的主要目的在于通过离散潜…

【动态规划】子序列问题(上)

1. 最长递增子序列 300. 最长递增子序列 和子数组不同的是&#xff0c;子数组要求是连续的&#xff0c;子序列只要下标是递增的就可以&#xff0c;这里严格递增的意思是不能有相等的元素&#xff0c;必须一直递增 状态表示&#xff1a;以 i 位置为结尾的所有的子序列中最长递…

Android GPU Inspector分析帧数据快速入门

使用 谷歌官方工具Android GPU Inspector (AGI) 可以对Android 应用进行深入和全面的系统性能分析和帧性能分析 。AGI 是一个非常强大的分析工具&#xff0c;尤其是在需要诊断 GPU 性能问题和优化应用时&#xff0c;可以帮助你精准找到性能瓶颈。本文介绍如何使用该工具对帧数据…

梳理一下spring中,与message相关的知识点

本次梳理的相关知识点包括jms&#xff0c;amqp(rabbitmq)&#xff0c;sping-messaging&#xff0c;spring-integration&#xff0c;springcloud-stream&#xff0c;这些都是与消息message相关的内容&#xff0c;它们有什么区别与联系呢&#xff1f; 相关的要点与相互关系都整理…

物联网消息队列Emqx日志配置及日志追踪以及Centos7上的rc.local开机不执行、git提交的小问题

一、物联网消息队列Emqx日志配置及日志追踪 EMQX支持将日志输出到控制台或者日志文件&#xff0c;或者同时使用两者。使用 Docker 部署 EMQX&#xff0c;默认只能通过 docker logs 命令查看 EMQX 日志。EMQX 的默认日志级别为 warning&#xff0c;默认在单日志文件超过10MB(log…

word压缩大小怎么弄?快来试试这几种压缩word方法!

word压缩大小怎么弄&#xff1f;在处理Word文档时&#xff0c;如果遇到体积过大的情况&#xff0c;无疑会带来一系列麻烦&#xff0c;大型Word文档不仅占据大量存储空间&#xff0c;而且在传输过程中会耗费更多时间&#xff0c;想象一下&#xff0c;当你急需将一份重要的文档发…

Perl打印9x9乘法口诀

本章教程主要介绍如何用Perl打印9x9乘法口诀。 一、程序代码 1、写法① use strict; # 启用严格模式&#xff0c;帮助捕捉变量声明等错误 use warnings; # 启用警告&#xff0c;帮助发现潜在问题# 遍历 1 到 9 的数字 for my $i (1..9) {# 对于每个 $i&#xff0c;遍历 1…

【设计模式系列】观察者模式

一、什么是观察者模式 观察者模式&#xff08;Observer Pattern&#xff09;是一种行为设计模式&#xff0c;它定义了对象之间的一对多依赖关系&#xff0c;当一个对象的状态发生变化时&#xff0c;所有依赖于它的对象都会得到通知并自动更新。这种模式也被称为发布-订阅模式&…

【AscendC算子开发】笔记2 算子高级开发和调试调优

算子调试 Tensor也可以通过特定的printf方法来打印&#xff0c;见上图。 gdb调试见上图。 为什么gdb调试无法成功&#xff0c;因为run.sh里面有两行export&#xff0c;如果直接通过.XX运行的话需要配置一下。 npu域也支持调试&#xff0c;可以使用上述的方法。 内存检测工…

AI自动生成PPT哪个软件好?智能生成PPT不再熬夜做课件

大概这世上&#xff0c;都是职场牛马对“PPT”这三个字母的头痛反应最大吧&#xff01; 是的&#xff0c;就连各个年级段的老师也是很头痛——愁着怎样能在排版整齐的情况下&#xff0c;将必考知识点都呈现在PPT每一张幻灯片页面里...... 近期打听到用人工智能生成ppt课件&am…

ProtoBuf 的含义和安装

ProtoBuf 是什么 Protocol Buffers 是 Google 的⼀种语⾔⽆关、平台⽆关、可扩展的序列化结构数据的⽅法&#xff0c;它可⽤ 于&#xff08;数据&#xff09;通信协议、数据存储等。 Protocol Buffers 类⽐于、 XML&#xff0c;是⼀种灵活&#xff0c;⾼效&#xff0c;⾃动化机…

Java项目-基于springboot框架的智慧外贸系统项目实战(附源码+文档)

作者&#xff1a;计算机学长阿伟 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、ElementUI等&#xff0c;“文末源码”。 开发运行环境 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringBoot、Vue、Mybaits Plus、ELementUI工具&#xff1a;IDEA/…

2024年最新苹果iOS证书申请创建App详细图文流程

iOS 证书设置指南&#xff1a; 对于开发者来说&#xff0c;在没有Mac电脑或对Xcode等开发工具不熟悉的情况下&#xff0c;如何快速完成IOS证书制作和IPA文件提交至开发者中心一直是一个难题。但是现在&#xff0c;有了初雪云提供的极简工具&#xff0c;您可以轻松实现这两个任…