简体   繁体   English

Java泛型Pair <String, String> 存储在HashMap中不能正确检索key-&gt; value

[英]Java generics Pair<String, String> stored in HashMap not retrieving key->value properly

Here's Pair.java 这是Pair.java

import java.lang.*; 
import java.util.*; 

public class Pair<TYPEA, TYPEB> implements Comparable< Pair<TYPEA, TYPEB> > {
  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<TYPEA, TYPEB> p1 ) { 
    System.out.println("in compareTo()");
    if ( null != p1 ) { 
      if ( p1.equals(this) ) { 
        return 0; 
      } else if ( p1.hashCode() > this.hashCode() ) { 
            return 1;
      } else if ( p1.hashCode() < this.hashCode() ) { 
        return -1;  
      }
    }
    return(-1);
  }
  public boolean equals( Pair<TYPEA, TYPEB> p1 ) { 
    System.out.println("in equals()");
    if ( null != p1 ) { 
      if ( p1.Key_.equals( this.Key_ ) && 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);
  }
}

Here's the testcase: 这是测试用例:

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<String, String> pair = new Pair<String, String>( key, value ); 

    assertTrue( pair.getKey().equals( key ) );
    assertTrue( pair.getValue().equals( value ) );
    assertTrue( pair.equals( new Pair<String, String>(key, value)) );
  }

  public void testPairCollection() { 

    HashMap< Pair<String, String>, String> hm1 = new HashMap<Pair<String,String>, String>(); 

    Pair<String, String> p1 = new Pair<String, String>("Test1", "Value1"); 
       hm1.put(p1, "ONE");  
    Pair<String, String> p2 = new Pair<String, String>("Test1", "Value2"); 
       hm1.put(p2, "TWO");  
    Pair<String, String> p3 = new Pair<String, String>("Test2", "Value1"); 
       hm1.put(p3, "THREE");    
    Pair<String, String> p4 = new Pair<String, String>("Test2", "Value2"); 
       hm1.put(p4, "FOUR"); 
    Pair<String, String> p5 = new Pair<String, String>("Test3", "Value1"); 
       hm1.put(p5, "FIVE"); 
    Pair<String, String> p6 = new Pair<String, String>("Test3", "Value2"); 
       hm1.put(p6, "SIX");  
    Pair<String, String> p7 = new Pair<String, String>("Test3", "Value3"); 
       hm1.put(p7, "SEVEN");    

    assertTrue( hm1.size() == 7 ); 

    Pair<String, String> pSrch = new Pair<String, String>("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"));

  } 
}

Here's my problem, the last hm1.containsKey call should (I naively expect) return the value stored where Pair<"Three", "Three"> is true - I should get a String with a value of "SEVEN". 这是我的问题,最后一个hm1.containsKey调用应该(我天真地期望)返回存储的值,其中Pair <“Three”,“Three”>为真 - 我应该得到一个值为“SEVEN”的字符串。 Here is the output: 这是输出:

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]     <--- Bug here?

Never reaches 
          String result = hm1.get( pSrch );

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. 那么p7.hashCode()和pSrch.hashCode()是相等的,p7.equals(pSrch)和pSrch.equals(p7),以及hm1.containsValue(p7)== true,我希望hm1.containsValue(pSrch) )也会返回true,但事实并非如此。 What am I missing? 我错过了什么?

You need to override the equals method from the java.lang.Object class. 您需要从java.lang.Object重写 equals方法。

Instead, you've overloaded the method with an additional version that takes a Pair . 取而代之的是,你已经超负荷的附加版本,需要一个方法Pair Totally different method that never gets called. 永远不会被称为完全不同的方法。 Replace your equals with something like this: 用这样的东西代替你的equals

@Override
public boolean equals(Object o) { 
  System.out.println("in equals()");
  if (o instanceof Pair) { 
    Pair<?, ?> p1 = (Pair<?, ?>) o;
    if ( p1.Key_.equals( this.Key_ ) && p1.Value_.equals( this.Value_ ) ) { 
      return(true);
    }
  }
  return(false);
}

To avoid this kind of mistake, use the @Override annotation on methods you intend to act as overrides. 要避免这种错误,请对要作为覆盖的方法使用@Override注释。 You'll get a compile time error when they don't. 如果没有,您将收到编译时错误。

You should have noticed that it does not print "in equals()" after "starting containsKey search2". 您应该注意到在“启动containsKey search2”之后它不会打印“in equals()”。 Also you could debug into HashMap to see that .equals() method is called and returns false. 您也可以调试HashMap以查看.equals()方法被调用并返回false。 That's because 那是因为

public boolean equals( Pair<TYPEA, TYPEB> p1 )

does NOT override 不会覆盖

public boolean equals(Object obj)

defined in java.lang.Object 在java.lang.Object中定义

Change your code to 将您的代码更改为

  public boolean equals( Object obj ) {
    if (!(obj instanceof Pair)) return false;
    Pair p1 = (Pair) obj;

and it works. 它的工作原理。 You can avoid such bugs in the future by putting @Override annotation before method that you think you are overriding. 您可以通过在您认为重写的方法之前放置@Override注释来避免此类错误。 If you are not actually overriding it, compiler will tell you. 如果你实际上没有覆盖它,编译器会告诉你。 This 这个

@Override public boolean equals( Pair<TYPEA, TYPEB> p1 )

causes compilation error. 导致编译错误。 This 这个

@Override public boolean equals( Object obj )

does not. 才不是。 Also good IDE (Intellij IDEA for example) shows which methods are overriden. 同样好的IDE(例如Intellij IDEA)显示覆盖了哪些方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM