【老白学 Java】HashSet 应用 - 卡拉 OK(五)

devtools/2024/12/23 17:00:43/

HashSet 应用 - 卡拉 OK(五)

码老白
文章来源:《Head First Java》修炼感悟。

通过前几篇文章,老白也了解了基本排序方法,接下来要讨论的是数据重复问题。 ArrayList 不会阻止添加重复数据,那是 Set 集合类的职责。 本篇文章我们就来了解一下 Set 集合相关特性。

一、两个对象怎样才算相等

假如有两个引用变量,那么怎样才算相等呢? 是引用到了堆上的同一个对象,还是两个对象都有相同成员? 下面分别说说两种情况:

1、引用相等

这种表示引用了堆上同一个对象,如果对两个引用调用 hashCode() 方法,必定会返回相同的 hashcode(堆上的每个对象都是唯一的),而此时使用 == 对两个引用变量进行比较肯定也是相等的,因为是同一个对象的字节组合。 例如:

java">if (obj1.hashCode() == obj2.hashCode() && obj1.equals(obje2)) {// 认为 obj1 与 obj2 相等
}

2、对象相等

这表示堆上的两个对象具有相同成员,从感官上认为相等。 由于 hashcode 的唯一性,这两个对象的 hashcode 并不相等,所以如果想让它们相等就必须覆盖掉从原始对象 Object 继承到的 hashCode()equals() 方法,重新实现让它们返回相同的 hashcodetrue。 例如覆盖 Song 类方法:

java">// 覆盖父类方法,传入的歌曲对象名与当前歌名进行比较
// 比较对象是 String 类型,String 已经覆盖过此方法,所以可以和直接调用
public boolean equals(Object song) {Song s = (Song) song;return this.getTitle().equals(s.getTitle());
}
// 覆盖父类方法,注意使用了同一个实例变量 title
// 同样的,String 也覆盖过 hashCode() 方法,可以直接调用
public int hashCode() {return title.hashCode();
}

经过以上处理后,即歌名相同就可以认为两个 Song 对象重复。

二、HashSet 如何判断对象是否重复

元素加入 HashSet 前,需要检查集合中是否存在相同的 hashcode 元素,如果没有则认为没有重复,可以直接加入;如果存在相同的 hashcode,还要进一步使用 equals() 检查是否真的相等,以此来确定是否重复加入对象。

所以,如果你希望曲目文件中不会出现相同歌名,就要覆盖掉 hashCode()equals() 方法,让 Java 认为不相同的两个 Song 对象变为相同的,从而只会添加一个到 HashSet 中。

1、更新后的曲目清单

Pink Moon/Nick Drake/5/80
Somersault/Zero 7/4/84
Shiva Moon/Prem Joshua/6/120
Circles/BT/5/110
Deep Channel/Afro Celts/4/120
Passenger/Headmix/4/100
Listen/Tahiti 80/5/90
Listen/Tahiti 80/5/90
Listen/Tahiti 80/5/90
Circles/BT/5/110

可以看到,这份清单中有些重复元素,接下来准备去掉这些重复曲目。

2、修改 Song 类代码

java">/*** 文件:Song.java** 描述:歌曲信息类,用于保存歌曲名称、歌手等信息。* 版本:v6.0*/
public class Song implements Comparable<Song> {// 定义歌曲信息String title;String artist;String rating;String bpm;// 默认构造方法public Song() {}// 构造器,新建对象时传入歌曲信息public Song(String t, String a, String r, String b) {title = t;artist = a;rating = r;bpm = b;}// 覆盖父类方法,传入的歌曲对象名与当前歌名进行比较// 比较对象是 String 类型,String 已经覆盖过此方法,所以可以和直接调用public boolean equals(Object song) {Song s = (Song) song;return this.getTitle().equals(s.getTitle());}// 覆盖父类方法,注意使用了同一个实例变量 title// 同样的,String 也覆盖过 hashCode() 方法,可以直接调用public int hashCode() {return title.hashCode();}// 实现接口方法public int compareTo(Song s) {return title.compareTo(s.getTitle());}// 返回歌曲名称public String getTitle() {return title;}// 返回歌手名称public String getArtist() {return artist;}// 返回歌曲等级public String getRating() {return rating;}// 返回歌曲节拍信息public String getBpm() {return bpm;}// 重写方法,返回歌曲标题public String toString() {return title;}
}

Song 类文件覆盖了 hashCode()equals() 方法,强制把歌名相同的 Song 当做重复元素,不会被加入 HashSet 中。

3、修改 Karaoke 类代码:

java">/*** 文件:Karaoke6.java* * 描述:模拟 KTV 曲目清单,学习使用集合排序。* 		使用 HashSet 替换 ArrayList,确保曲目清单中不会出现重复歌曲。* 版本:v6.0*/
import java.io.*;
import java.util.*;public class Karaoke6 {/*** 用于对歌手名字进行比较的内部类,实现了Comparator接口*/class ArtistCompare implements Comparator<Song> {// 对传入的Song对象的歌手名字的字符串进行比较// 并返回一个整数值给 Collections 的比较方法public int compare(Song one, Song two) {return one.getArtist().compareTo(two.getArtist());}}// 用来保存所有曲目的列表ArrayList<Song> tracks = new ArrayList<Song>();// 执行入口public void go() {loadSongs();// 原始顺序System.out.println("original: " + tracks);// 按曲目排序// Collections.sort(tracks);// System.out.println("by title: " + tracks);// 使用了 HashSet,把曲目清单全部添加到 Set 集合中HashSet<Song> songSet = new HashSet<Song>();songSet.addAll(tracks);System.out.println("using Set: " + songSet);// 按歌手名字排序// ArtistCompare ac = new ArtistCompare();// Collections.sort(tracks, ac);// System.out.println("by artist: " + tracks);}// 载入曲目文件private void loadSongs() {try {// 先不理会下面语句的含义,// 只需知道能读取 songs.txt 文件内容就可以了File file = new File("songs.txt");BufferedReader reader = new BufferedReader(new FileReader(file));String line = null;while ((line = reader.readLine()) != null) {addSong(line);}} catch (Exception e) {e.printStackTrace();}}// 解析曲目private void  addSong(String token) {String[] tokens = token.split("/");Song s = new Song(tokens[0], tokens[1], tokens[2], tokens[3]);tracks.add(s);}// 程序入口public static void main(String[] args) {new Karaoke6().go();}
}

代码使用 HashSet 替代 ArrayList。

4、编译执行

HashSet没有重复元素可以看到,CirclesListen 的重复元素已经被去除。 目前代码还没有经过排序,这是按原始顺序输出的结果。

三、关于 hashCode 和 equals 的绕口令

  • 相同 hashcode 值的两个对象并不一定相等;
  • 如果两个对象相等,则 hashcode 必定也相等;
  • 如果两个对象相等,其一使用 equals() 必定返回 true,反之亦然;
  • 如果 equals() 被覆盖,则 hashCode() 也必须覆盖;
  • hashcode 是唯一的,如果没有覆盖 hashCode() 方法,两个对象无论如何也不会认为是相等的;
  • equals() 用于测试两个引用变量是否引用同一个对象,如果没有覆盖这个方法,那么两个对象永远不会认为是相等的;
  • 如果 equals()true,那么 hashCode() 必定相等;而如果 hashCode() 相等则不一定 equals()true

结束语

从下一篇开始,老白会使用另一种集合类进行无重复排序,请保持关注。


《 上一篇 泛型应用 - 卡拉 OK(四)下一篇 TreeSet 应用 - 卡拉 OK(六) 》

http://www.ppmy.cn/devtools/144744.html

相关文章

React工具和库面试题目(二)

1. 使用 Webpack 打包 React 项目时&#xff0c;如何减小生成的 JavaScript 文件大小? 为了减小生成的 JavaScript 文件大小&#xff0c;可以采取以下几种策略&#xff1a; 1.1 代码分割&#xff08;Code Splitting&#xff09; Webpack 支持通过 动态导入 和 React.lazy 等…

#渗透测试#漏洞挖掘#红蓝攻防#护网#sql注入介绍03-SQL注入联合查询注入(Union-Based SQL Injection)

免责声明 本教程仅为合法的教学目的而准备&#xff0c;严禁用于任何形式的违法犯罪活动及其他商业行为&#xff0c;在使用本教程前&#xff0c;您应确保该行为符合当地的法律法规&#xff0c;继续阅读即表示您需自行承担所有操作的后果&#xff0c;如有异议&#xff0c;请立即停…

Web Dev Tools Android 项目常见问题解决方案

Web Dev Tools Android 项目常见问题解决方案 web-dev-tools-android Sample Android Application - MVVM, Clean Architecture, Modularization, Repository Pattern [这里是图片001] 项目地址: https://gitcode.com/gh_mirrors/we/web-dev-tools-android 项目基础介绍 Web…

C05S09-Keepalive服务架设

一、Keepalive 1. Keepalive概述 代理服务器和调度器都是单点模式&#xff0c;Keepalive是一种实现LVS调度器实现高可用集群的架设&#xff0c;以提高节点的冗余和容错。 Keepalive是一种基于VRRP协议实现的调度器高可用方案&#xff0c;为了实现LVS的集群而设计开发&#x…

计算机基础复习12.22

Redis实现分布式锁 set lock_key unique_value nx px 10000 lock_key: key键 unique_value:是唯一的标识 nx: 表示lock_key不存在&#xff0c;才对lock_key进行设置 px: 设置过期时间 Linux的排查命令 top 实时监控进程 显示CPU 内存 负载 交换区 netstat:查看网络连接…

Flutter组件————Scaffold

Scaffold Scaffold 是一个基础的可视化界面结构组件&#xff0c;它实现了基本的Material Design布局结构。使用 Scaffold 可以快速地搭建起包含应用栏&#xff08;AppBar&#xff09;、内容区域&#xff08;body&#xff09;、抽屉菜单&#xff08;Drawer&#xff09;、底部导…

解决QT制作的软件,全屏显示后最小化,点击任务栏图标打开时不是全屏而是窗口状态的问题

问题&#xff1a; 用QT自定义窗口写最大最小化时&#xff0c;发现从全屏切换到最小化状态&#xff0c;再从任务栏点击图标时&#xff0c;打开的窗体状态是窗口化状态而不是全屏状态。 自定义的窗体切换函数DoVideoBoxMenu_WindowState(Qt::WindowState wState)&#xff0c;根据…

SonarQube 概述

**SonarQube ** 1. SonarQube 概述 SonarQube 是一个开源的代码质量管理平台&#xff0c;广泛用于持续检查代码的质量&#xff0c;包括检测代码中的错误、漏洞和不符合最佳实践的代码。SonarQube 可以与 CI/CD 流程结合&#xff0c;自动化地对代码进行静态分析&#xff0c;帮…