Java HashSet contains方法异常:应为false却返回true
问题根源与修复方案
核心问题
你的代码出现结果不一致的原因在于Triple类的equals方法违反了Java中equals约定的对称性原则,同时缺少必要的类型检查:
对称性破坏:
- 当HashSet执行
contains(triple2)时,实际是用triple2.equals(triple1)来判断。此时triple2的equals方法会检查triple1的列表是否包含triple2的所有元素(0、0、0),triple1的列表[-4,0,4]包含0,所以返回true。 - 而
Objects.equals(triple1, triple2)是调用triple1.equals(triple2),此时会检查triple2的列表是否包含triple1的所有元素(-4、0、4),triple2的列表[0,0,0]不包含-4和4,所以返回false。
这就导致两种判断逻辑的结果完全相反。
- 当HashSet执行
缺少类型检查:如果向equals方法传入非Triple类型的对象,会直接抛出
ClassCastException,不符合equals方法的规范。equals逻辑不符合预期:当前用
contains判断元素存在的逻辑,无法区分元素数量和顺序,比如Triple(0,1,1).equals(Triple(0,0,0))会返回true,这显然不是合理的相等判断。
修复方案
根据你的实际需求,提供两种修复方式:
需求1:三元组元素顺序一致时判定相等
import java.util.ArrayList; import java.util.List; import java.util.Objects; class Triple { private final List<Integer> triple; public Triple(int one, int two, int three) { this.triple = new ArrayList<>(); this.triple.add(one); this.triple.add(two); this.triple.add(three); } @Override public int hashCode() { // 使用Objects.hash生成低冲突的哈希值 return Objects.hash(triple.get(0), triple.get(1), triple.get(2)); } @Override public boolean equals(Object o) { // 引用直接相等,返回true if (this == o) return true; // 类型不符或为空,返回false if (o == null || getClass() != o.getClass()) return false; Triple other = (Triple) o; // 利用List的equals方法按顺序比较元素 return triple.equals(other.triple); } }
需求2:三元组元素相同(不考虑顺序,需匹配重复次数)时判定相等
import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Objects; class Triple { private final List<Integer> triple; // 缓存排序后的列表,避免每次equals都重复排序 private final List<Integer> sortedTriple; public Triple(int one, int two, int three) { this.triple = new ArrayList<>(); this.triple.add(one); this.triple.add(two); this.triple.add(three); this.sortedTriple = new ArrayList<>(triple); Collections.sort(sortedTriple); } @Override public int hashCode() { // 基于排序后的列表生成哈希值,保证相等对象的哈希值一致 return Objects.hash(sortedTriple.get(0), sortedTriple.get(1), sortedTriple.get(2)); } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Triple other = (Triple) o; // 比较排序后的列表,忽略原始顺序 return sortedTriple.equals(other.sortedTriple); } }
修复后效果
修复后的代码满足Java的equals/hashCode约定:
- equals方法具备对称性、自反性和传递性;
- hashCode与equals逻辑一致,相等的对象哈希值一定相等;
- HashSet的
contains方法与Objects.equals的结果会完全一致。
内容的提问来源于stack exchange,提问作者andrew_lau
相关产品推荐
相关产品推荐

