Java中年月元组的hashCode实现方案(用于重复组合判断)
嘿,这个问题问到点子上了!正好《Effective Java》里的哈希码实现准则完全适配你的年月对象场景,我给你拆解一下怎么写,连带着把equals也补上——毕竟这俩方法是绑定在一起的,缺一不可~
第一步:定义你的年月对象并实现核心方法
首先先把包含year和month的类写出来,参数校验、equals、hashCode一个都不能少:
public class YearMonthPair { // 用final修饰保证不可变性,这对哈希表的稳定性很重要 private final int year; private final int month; public YearMonthPair(int year, int month) { // 先做参数校验,避免无效的月份值混入 if (month < 1 || month > 12) { throw new IllegalArgumentException("Month must be between 1 and 12"); } this.year = year; this.month = month; } // 先实现equals,因为hashCode必须和equals逻辑保持一致 @Override public boolean equals(Object o) { // 先判断是否是同一个对象,快速返回 if (this == o) return true; // 空值或者类不匹配直接返回false if (o == null || getClass() != o.getClass()) return false; // 强转后比较两个核心字段 YearMonthPair that = (YearMonthPair) o; return year == that.year && month == that.month; } // 重点:按照《Effective Java》推荐实现hashCode @Override public int hashCode() { // 初始值用第一个字段year int result = year; // 用31作为乘数,然后加上第二个字段month result = 31 * result + month; return result; } // 可选:重写toString方便调试和打印 @Override public String toString() { return year + ":" + String.format("%02d", month); } }
为什么这么实现hashCode?
这完全是遵循《Effective Java》里的经典原则:
- 一致性:如果两个对象通过
equals()判断相等,它们的hashCode()必须返回相同的值;反之,不等的对象尽量返回不同的哈希值(减少碰撞)。 - 选择31作为乘数:31是一个奇素数,一方面能有效减少不同组合产生相同哈希值的概率,另一方面JVM会自动把
31 * result优化为(result << 5) - result(左移5位等于乘32,减1就是乘31),效率很高。 - 字段组合逻辑:先以year为基础,再叠加month,确保不同的年月组合(比如2018:03和2018:04、2017:12和2018:01)能生成差异化的哈希值。
实际使用示例
你可以直接把这个对象放进HashSet里完成去重操作,或者用HashMap做键:
import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; public class Demo { public static void main(String[] args) { List<String> rawYearMonthList = Arrays.asList("2018:03", "2019:05", "2018:03", "2020:12", "2019:05"); Set<YearMonthPair> uniquePairs = new HashSet<>(); for (String s : rawYearMonthList) { String[] parts = s.split(":"); int year = Integer.parseInt(parts[0]); int month = Integer.parseInt(parts[1]); uniquePairs.add(new YearMonthPair(year, month)); } // 输出去重后的结果 uniquePairs.forEach(System.out::println); } }
额外小提示
如果你用的是Java 8及以上版本,其实不用自己写这个类!JDK自带的java.time.YearMonth已经完美实现了equals()和hashCode(),还自带了很多日期处理的方法,直接用它更省心:
import java.time.YearMonth; // 直接创建实例 YearMonth ym = YearMonth.of(2018, 3); // 放进HashSet去重完全没问题 Set<YearMonth> uniqueYmSet = new HashSet<>();
内容的提问来源于stack exchange,提问作者JacksOnF1re
相关产品推荐
相关产品推荐

