I've read that a (custom) class created without overriding hashCode() and equals() methods can lead to memory leaks. Specifically, putting an object of such a class into a HashSet twice will result in the first object leaking because replaced by the second object (whose hash code isn't different?).

For example, ...

Code:
public class Key
{
  public String key;
  public Key( String key ) { Key.key = key; }
}
 
@Test( expected = OutOfMemoryError.class )
public void test_willLeakMemory()
{
  Map< Object, Object > map = System.getProperties();
 
  while( true )
    map.put( new Key( "key" ), "value" );
}
How and why is this the case?