Copies.Copy.equals(Object) in src/main/java/io/zold/api/Copies.java lines 117-120 declares two Copy instances equal when this.compareTo((Copy) obj) == 0, and compareTo at lines 112-114 compares the two copies by their score(). The neighbouring hashCode() at lines 123-125, however, returns this.wlt.hashCode(), derived from the wallet object rather than the score.
The two definitions are not aligned, so two Copy instances that carry different wallets but the same summed score satisfy a.equals(b) == true while a.hashCode() != b.hashCode(). That contradicts the contract documented on java.lang.Object.hashCode, which requires equal objects to return equal hash codes, and breaks any HashMap, HashSet, or Hashtable that stores Copy values, since the bucket lookup uses the hash and never reaches the equals check.
The smallest fix is to derive both methods from the same field. Either replace the body of hashCode() with this.score().hashCode() so it tracks the same projection as equals, or rewrite equals to compare wallets so it tracks the same projection as hashCode. The choice depends on whether Copy identity is meant to be the wallet or the score it ranks by.
Copies.Copy.equals(Object)insrc/main/java/io/zold/api/Copies.javalines 117-120 declares twoCopyinstances equal whenthis.compareTo((Copy) obj) == 0, andcompareToat lines 112-114 compares the two copies by theirscore(). The neighbouringhashCode()at lines 123-125, however, returnsthis.wlt.hashCode(), derived from the wallet object rather than the score.The two definitions are not aligned, so two
Copyinstances that carry different wallets but the same summed score satisfya.equals(b) == truewhilea.hashCode() != b.hashCode(). That contradicts the contract documented onjava.lang.Object.hashCode, which requires equal objects to return equal hash codes, and breaks anyHashMap,HashSet, orHashtablethat storesCopyvalues, since the bucket lookup uses the hash and never reaches theequalscheck.The smallest fix is to derive both methods from the same field. Either replace the body of
hashCode()withthis.score().hashCode()so it tracks the same projection asequals, or rewriteequalsto compare wallets so it tracks the same projection ashashCode. The choice depends on whetherCopyidentity is meant to be the wallet or the score it ranks by.