title: Java generics Pair<String, String> stored in HashMap not retrieving key->value properly
body: <p>Here's Pair.java</p>
  
  <pre><code>import java.lang.*; 
  import java.util.*; 
  
  public class Pair&lt;TYPEA, TYPEB&gt; implements Comparable&lt; Pair&lt;TYPEA, TYPEB&gt; &gt; {
    protected final TYPEA Key_;
    protected final TYPEB Value_;
  
    public Pair(TYPEA key, TYPEB value) {
      Key_   = key;
      Value_ = value;
    }
    public TYPEA getKey() {
      return Key_;
    }
    public TYPEB getValue() {
      return Value_;
    }
    public String toString() {
      System.out.println("in toString()");
      StringBuffer buff = new StringBuffer();
        buff.append("Key: ");
        buff.append(Key_);
        buff.append("\tValue: ");
        buff.append(Value_);
      return(buff.toString() );
    }
    public int compareTo( Pair&lt;TYPEA, TYPEB&gt; p1 ) { 
      System.out.println("in compareTo()");
      if ( null != p1 ) { 
        if ( p1.equals(this) ) { 
          return 0; 
        } else if ( p1.hashCode() &gt; this.hashCode() ) { 
              return 1;
        } else if ( p1.hashCode() &lt; this.hashCode() ) { 
          return -1;  
        }
      }
      return(-1);
    }
    public boolean equals( Pair&lt;TYPEA, TYPEB&gt; p1 ) { 
      System.out.println("in equals()");
      if ( null != p1 ) { 
        if ( p1.Key_.equals( this.Key_ ) &amp;&amp; p1.Value_.equals( this.Value_ ) ) { 
          return(true);
        }
      }
      return(false);
    }
    public int hashCode() { 
      int hashCode = Key_.hashCode() + (31 * Value_.hashCode());
      System.out.println("in hashCode() [" + Integer.toString(hashCode) + "]");
      return(hashCode);
    }
  }
  </code></pre>
  
  <p>Here's the testcase: </p>
  
  <pre><code>import java.lang.*; 
  import java.util.*;
  
  import junit.framework.*;
  
  public class PairTest extends TestCase { 
  
    public void testPair() { 
      String key   = new String("key"); 
      String value = new String("asdf"); 
  
      Pair&lt;String, String&gt; pair = new Pair&lt;String, String&gt;( key, value ); 
  
      assertTrue( pair.getKey().equals( key ) );
      assertTrue( pair.getValue().equals( value ) );
      assertTrue( pair.equals( new Pair&lt;String, String&gt;(key, value)) );
    }
  
    public void testPairCollection() { 
  
      HashMap&lt; Pair&lt;String, String&gt;, String&gt; hm1 = new HashMap&lt;Pair&lt;String,String&gt;, String&gt;(); 
  
      Pair&lt;String, String&gt; p1 = new Pair&lt;String, String&gt;("Test1", "Value1"); 
         hm1.put(p1, "ONE");  
      Pair&lt;String, String&gt; p2 = new Pair&lt;String, String&gt;("Test1", "Value2"); 
         hm1.put(p2, "TWO");  
      Pair&lt;String, String&gt; p3 = new Pair&lt;String, String&gt;("Test2", "Value1"); 
         hm1.put(p3, "THREE");    
      Pair&lt;String, String&gt; p4 = new Pair&lt;String, String&gt;("Test2", "Value2"); 
         hm1.put(p4, "FOUR"); 
      Pair&lt;String, String&gt; p5 = new Pair&lt;String, String&gt;("Test3", "Value1"); 
         hm1.put(p5, "FIVE"); 
      Pair&lt;String, String&gt; p6 = new Pair&lt;String, String&gt;("Test3", "Value2"); 
         hm1.put(p6, "SIX");  
      Pair&lt;String, String&gt; p7 = new Pair&lt;String, String&gt;("Test3", "Value3"); 
         hm1.put(p7, "SEVEN");    
  
      assertTrue( hm1.size() == 7 ); 
  
      Pair&lt;String, String&gt; pSrch = new Pair&lt;String, String&gt;("Test3", "Value3"); 
      assertTrue( p7.equals(pSrch) );
      assertTrue( pSrch.equals(p7) );
      assertTrue( p7.hashCode() == pSrch.hashCode() ); 
      assertTrue( 0 == p7.compareTo( pSrch ) );
      assertTrue( 0 == pSrch.compareTo(p7) );
  
      System.out.println("starting containsKey search");
      assertTrue( hm1.containsKey( p7 ) );
      System.out.println("starting containsKey search2");
      assertTrue( hm1.containsKey( pSrch ) );
      System.out.println("finishing containsKey search");
  
      String result = hm1.get( pSrch );
      assertTrue( null != result );
      assertTrue( 0 == result.compareTo("SEVEN"));
  
    } 
  }
  </code></pre>
  
  <p>Here's my problem, the last hm1.containsKey call should (I naively expect) return the value stored where Pair&lt;"Three", "Three"> is true - I should get a String with a value of "SEVEN".  Here is the output: </p>
  
  <pre><code>Running in equals()
  in hashCode() [1976956095]
  in hashCode() [1976956126]
  in hashCode() [1976956096]
  in hashCode() [1976956127]
  in hashCode() [1976956097]
  in hashCode() [1976956128]
  in hashCode() [1976956159]
  in equals()
  in equals()
  in hashCode() [1976956159]
  in hashCode() [1976956159]
  in compareTo()
  in equals()
  in compareTo()
  in equals()
  starting containsKey search
  in hashCode() [1976956159]
  starting containsKey search2
  in hashCode() [1976956159]     &lt;--- Bug here?
  
  Never reaches 
            String result = hm1.get( pSrch );
  </code></pre>
  
  <p>So is both p7.hashCode() and pSrch.hashCode() are equal and p7.equals(pSrch) and pSrch.equals(p7), and hm1.containsValue(p7) == true, I would expect hm1.containsValue(pSrch) would also return true, but it does not.  What am I missing? </p>