Java泛型对存储在HashMap中的不能正确检索key-> value

时间:2021-12-22 19:16:08

Here's 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". Here is the output:

这是我的问题,最后一个hm1.containsKey调用应该(我天真地期望)返回存储的值,其中Pair <“Three”,“Three”>为真 - 我应该得到一个值为“SEVEN”的字符串。这是输出:

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. What am I missing?

那么p7.hashCode()和pSrch.hashCode()是相等的,p7.equals(pSrch)和pSrch.equals(p7),以及hm1.containsValue(p7)== true,我希望hm1.containsValue(pSrch) )也会返回true,但事实并非如此。我错过了什么?

2 个解决方案

#1


24  

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. Totally different method that never gets called. Replace your equals with something like this:

相反,您已经使用带有对的附加版本重载了该方法。永远不会被称为完全不同的方法。用这样的东西代替你的平等:

@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. You'll get a compile time error when they don't.

要避免这种错误,请对要作为覆盖的方法使用@Override注释。如果没有,您将收到编译时错误。

#2


5  

You should have noticed that it does not print "in equals()" after "starting containsKey search2". Also you could debug into HashMap to see that .equals() method is called and returns false. That's because

您应该注意到在“启动containsKey search2”之后它不会打印“in equals()”。您也可以调试HashMap以查看.equals()方法被调用并返回false。那是因为

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. If you are not actually overriding it, compiler will tell you. This

它的工作原理。您可以通过在您认为重写的方法之前放置@Override注释来避免此类错误。如果你实际上没有覆盖它,编译器会告诉你。这个

@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)显示了覆盖哪些方法。

#1


24  

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. Totally different method that never gets called. Replace your equals with something like this:

相反,您已经使用带有对的附加版本重载了该方法。永远不会被称为完全不同的方法。用这样的东西代替你的平等:

@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. You'll get a compile time error when they don't.

要避免这种错误,请对要作为覆盖的方法使用@Override注释。如果没有,您将收到编译时错误。

#2


5  

You should have noticed that it does not print "in equals()" after "starting containsKey search2". Also you could debug into HashMap to see that .equals() method is called and returns false. That's because

您应该注意到在“启动containsKey search2”之后它不会打印“in equals()”。您也可以调试HashMap以查看.equals()方法被调用并返回false。那是因为

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. If you are not actually overriding it, compiler will tell you. This

它的工作原理。您可以通过在您认为重写的方法之前放置@Override注释来避免此类错误。如果你实际上没有覆盖它,编译器会告诉你。这个

@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)显示了覆盖哪些方法。