Why won't my HashSet allow me to add two of the same instance, if their equals() says they're false?

equals, hashset, java, set

Solution

HashSet (really HashMap under the hood) has an "optimization" in that it checks for object reference equality before calling the `equals()` method. since you are putting the same instance in twice, they are considered equal even though the `equals()` method does not agree.

Relevant line from HashMap.put():

        if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {

Problem

The documentation for `HashSet.add` says Adds the specified element to this set if it is not already present. More formally, adds the specified element e to this set if this set contains no element e2 such that (e==null ? e2==null : e.equals(e2)). If this set already contains the element, the call leaves the set unchanged and returns false. Since my code below will return false for `e.equals(e2)`, I'd expect it to let me add the same instance twice. But the set only contains my instance once. Can someone explain why? ``` package com.sandbox; import java.util.HashSet; import java.util.Set; public class Sandbox { public static void main(String[] args) { Set<A> as = new HashSet<A>(); A oneInstance = new A(); System.out.println(oneInstance.equals(oneInstance)); //this prints false as.add(oneInstance); as.add(oneInstance); System.out.println(as.size()); //this prints 1, I'd expect it to print 2 since the System.out printed false } private static class A { private Integer key; @Override public boolean equals(Object o) { if (!(o instanceof A)) { return false; } A a = (A) o; if (this.key == null || a.key == null) { return false; //the key is null, it should return false } if (key != null ? !key.equals(a.key) : a.key != null) { return false; } return true; } @Override public int hashCode() { return key != null ? key.hashCode() : 0; } } } ```

Original source

Related problems