上代码!
import java.util.*;
public class hashSetExample {
/*
* 如果我们只需要存储不重复的key,并不需存储映射的 value,可以使用 set
* set 用于存储不重复的元素集合,主要提供以下几个方法:
* - 将元素添加进Set<E>: boolean add(E e)
* - 将元素从 Set<E> 删除:boolean remove(Object e)
* - 判断是否包含元素:Boolean contains(Object e)
* */
public static void main(String[] args) {
/*
* Set 接口并不保证有序,而 SortedSet 接口则保证元素是有序的
* - HashSet 是无序的,因为它实现了 set 接口,并没有实现 sortedset 接口
* - TreeSet 是有序的,因为它实现了 sortedset 接口
* */
/*
* 练习:在聊天软件中,发送放发送消息时,遇到网络超时后会自动重发,因此,接收方可能会收到重复的消息,在显示给用户看的时候,
* 需要首先去重。使用 set 去重
* */
List<Message> received = new ArrayList<>();
received.add(new Message(1,"今天是几月几号啊?"));
received.add(new Message(2,"今天是20240121"));
received.add(new Message(3,"你们什么时候放假"));
received.add(new Message(4,"请假两天吧,2月"));
received.add(new Message(4,"请假两天吧,2月"));
received.add(new Message(4,"请假两天吧,2月"));
received.add(new Message(5,"那就是明天开始抢票了"));
// 这里最开始发现一个问题就是,ArrayList 转 hashSet 的时候,因为作为key 是一个类,所以转成 hashSet 之后并没有去重
// 原因是:作为key的类没有实现 equals 和 hashCode 方法,
// 一定要记住!!! 作为key 的类如果没有实现这两个方法,这两个方法在 hashSet 中用于判断元素的唯一性。没有实现则无法去重
HashSet<Message> SetRecevied = new HashSet<>(received);
// SetRecevied.addAll(received);
for (Message msg:SetRecevied){
System.out.println(msg.toString());
}
System.out.println("-----------------分割线------------------");
/*
* 下面是将上面的无需set集合(去重过的),进行排序,再进行输除
* 思路:hashSet > ArrayList > Collection.sort(ArrayList对象) 进行排序
* 注意: 这里要给Message类实现一个 Comparator 接口,MyClassComparator类。
* 这个类是另外定义的,不能在Message类中进行定义。
* */
List<Message> setList = new ArrayList<>(SetRecevied);
Comparator<Message> myClassComparator = new MyClassComparator();
Collections.sort(setList,myClassComparator);
for(Message msg : setList){
System.out.println(msg.toString());
}
}
}
class Message{
public final int sequence;
public final String text;
Message(int sequence, String text) {
this.sequence = sequence;
this.text = text;
}
public String toString(){
return this.sequence + "_" + this.text;
}
@Override
public int hashCode(){
// 选择一个初始值,这个值要是质数,质数17最常用,表现也最好。因为质数具有良好的分布特性
int result = 17;
// 乘以31是为了避免相邻的哈希值太相似
result = 31 * result + sequence;
result = 31 * result + (text == null ? 0 : text.hashCode());
return result;
}
@Override
public boolean equals(Object obj){
if (this == obj){
return true;
}
if (obj == null || getClass() != obj.getClass()){
return false;
}
// 将对象转换为相应的类
Message msg = (Message) obj;
// 根据类的实际需求,比对类的各个属性是否相等。
return sequence == msg.sequence && text.equals(msg.text);
}
/*
* 关于以上 hashCode 和 equals 方法实现:
* hashCode:
* 1、初始值 result :哈希码的初始值,通常选择一个质数,这里是17,因17表现良好。
* 2、乘以 31 :选择 31 是因为它是一个奇质数,而且 31 * result 可以被 JVM 优化为 (result << 5) - result,这样可以更高效地计算。
* 3、属性 name 的哈希码:使用三元运算符 (text == null ? 0 : text.hashCode()) 来获取属性 name 的哈希码。如果 name 为null,则使用 0 作为哈希码,否则使用 name 的哈希码。
* 4、组合到最终的哈希码中:将前面计算得到的结果与属性 name 的哈希码相加,得到最终的哈希码,并将其复制给 result。
* */
}
/*
* 需要单独创建一个类,实现Comparator 接口,不能在被实例的类中进行实现Comparator 方法。
* */
class MyClassComparator implements Comparator<Message>{
@Override
public int compare(Message obj1,Message obj2){
return Integer.compare(obj1.sequence,obj2.sequence);
}
}