簡體   English   中英

在復合 object 的 HashMap 中找不到密鑰

[英]Key not found in a HashMap for a composite object

所以,我在 Java 中創建了自己的復合鍵,有 3 個成員

public class MyOwnKey{
int location;
int length;
String [] tokens;
}

現在我使用構造函數創建兩個對象

String [] tokens = "Stackoverflow is great".split("\\s+");
Object key1 = new MyOwnKey(0,0,tokens)
tokens = "Web is great".split("\\s+");
Object key2 = new MyOwnKey(0,0,tokens)

現在,我在 HashMap HashMap map = new HashMap(); map.put(key1,1);

現在,當我確實包含密鑰時,這就是問題,它給出了錯誤;

**map.containsKey(key2) //returns false whereas it should return true.**

只是為了讓它有意義:

key1.equals(key2) returns true

並且哈希碼代碼也相等。 key1.hashCode() == key2.hashCode().

我已經實現了我自己的 hashCode 版本,toEquals() 和 toCompare()。

不知道有什么問題。

這是代碼

import java.io.DataOutput;
import java.io.DataInput;
import java.io.IOException;

import org.apache.hadoop.io.WritableComparable;

public class PatternGeneratorKey implements WritableComparable<Object> {


    private String [] tokens;
    int location;
    int length;

    StringBuffer _toString = null;

    public PatternGeneratorKey(){
        tokens = new String[1];
        location =0;
        length=1;
    }

    public PatternGeneratorKey(int location, int length, String [] tokens){

        this.location = location;
        this.length = length;

        this.tokens=  new String[tokens.length];
        for(int i = 0; i < tokens.length;i++){
            this.tokens[i] = tokens[i];
        }

    }

    public int compareTo(Object o) {
        if (!(o instanceof PatternGeneratorKey))
            return -1;
        return this.compareTo((PatternGeneratorKey) o);
    }

    public void write(DataOutput out) throws IOException {

        out.writeInt(tokens.length);
        for(int i = 0; i<tokens.length;i++){
            out.writeUTF(tokens[i]);

        }
        out.writeInt(location);
        out.writeInt(length);
    }

    public void readFields(DataInput in) throws IOException {

        int l = in.readInt();

        tokens = new String[l];
        for(int i = 0; i < l ; i++){
            tokens[i] = in.readUTF();
        }
        location = in.readInt();
        length = in.readInt();
    }

    public int compareTo(PatternGeneratorKey k) {

        if(this.tokens.length - this.length != k.tokens.length - k.length){
            return this.tokens.length - this.length -( k.tokens.length - k.length);
        }

        if(this.location != k.location){
            return this.location  - k.location;
        }

        int i = 0 , j= 0;
        for(i = 0, j=0 ; i < this.tokens.length && j < k.tokens.length;){

            if(i == this.location ){
                i = i + length;
                continue;
            }
            if( j == k.location){
                j = j + k.length;
                continue;
            }
            if(!this.tokens[i].equalsIgnoreCase(k.tokens[j])){
                return this.tokens[i].compareTo(k.tokens[j]);
            }else{
                i++;
                j++;
            }
        }


        //TODO: add comparison on left out phrase
        return 0;
    }

    public int hashCode() {
        int hashCode=0;     
        for(int i = 0; i < tokens.length;){

            if(i == location ){

                i = i + length;
                continue;
            }
            hashCode += tokens[i++].hashCode();
        }

        hashCode+= location + tokens.length;
        return hashCode;
    }


    public String toString(){

        if(_toString == null){
            _toString = new StringBuffer();
            for(int k = 0; k < tokens.length ;k++){
                if(k==location){
                    _toString.append(":").append(" ");
                    k=k+length-1;
                }else{
                    _toString.append(tokens[k]).append(" ");
                }
            }
        }

        return _toString.toString();
    }

    public boolean equals(PatternGeneratorKey k) {

        if(this.tokens.length - this.length == k.tokens.length - k.length 
                && this.location == k.location){

            //assume second one is larger
            String tokens[] = k.tokens;
            int length = k.length;
            int location = k.location;

            String [] tokens1 = this.tokens;
            int length1 = this.length;
            int location1 = this.location;
            //make the local variable point to the largest of the two
            if( this.tokens.length > k.tokens.length){
                tokens = this.tokens;
                length = this.length;
                location = this.location;
                tokens1 = k.tokens;
                length1 = k.length;
                location1 = k.location;

            }

            int i = 0 , j= 0;
            for(i = 0, j=0 ; i < tokens.length;){

                if(i == location ){

                    i = i + length;
                    continue;
                }
//              if( j >= location1 && j<= location1 + length1 -1){
                if( j == location1){
                    j = j + length1;
                    continue;
                }
                if(!tokens[i++].equalsIgnoreCase(tokens1[j++])){
                    return false;
                }
            }
            return true;
        }else{
            return false;
        }
    }
}

而且,這是我正在測試的代碼

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.hadoop.io.Text;


public class Test {

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub

        String value = "gm used cars";
        // Compile all the words using regex
        String[] tokens = value.toString().split("\\s+");

        //to find pattern we need atleast two words in the query
        if(tokens.length <=1){
            return;
        }

        Map<PatternGeneratorKey,List> map = new HashMap<PatternGeneratorKey, List>();

        for(int l = 1 ; l < tokens.length; l++){
            for(int i = 0 ; i < tokens.length - (l-1); i++){
                String hit = new String(getPhrase(l, i, tokens));
                PatternGeneratorKey key1 = new PatternGeneratorKey(i, l, tokens);
                List list = null;
                for(int k = 0;k< tokens.length;k++){
                    System.out.println("i:" + i + ",l:" + l + ",tokens:" + tokens[k]);
                }
                System.out.println("hashcode:" + key1.hashCode());

                if(!map.containsKey(key1)){
                    list = new ArrayList<String>();
                    map.put(key1, list);
                }else{
                    list = (List) map.get(key1);
                }
                list.add(hit);
            }
        }
            value = "ford used cars";
            String[] tokens2= value.toString().split("\\s+");

            PatternGeneratorKey key2 = new PatternGeneratorKey(0, 1, tokens);

            //run a sliding window for length 1 to tokens length -1
            for(int l = 1 ; l < tokens2.length; l++){
                //genereate token pairs with sliding window. 
                for(int i = 0 ; i < tokens2.length - (l-1); i++){
                    //hit a single token or a + b if there are two.
                    String hit = new String(getPhrase(l, i, tokens2));
                    PatternGeneratorKey key1 = new PatternGeneratorKey(i, l, tokens2);

                    System.out.println();

                    System.out.println(key1.toString() + "|" + key2.toString() + "|"+ key1.equals(key2));
                    for(int k = 0;k< tokens2.length;k++){
                        System.out.println("i:" + i + ",l:" + l + ",tokens:" + tokens2[k]);
                    }
                    System.out.println("hashcode:" + key1.hashCode());

                    List list = null;
                    if(!map.containsKey(key1)){
                        list = new ArrayList<String>();
                        map.put(key1, list);
                    }else{
                        list = (List) map.get(key1);
                    }
                    list.add(hit);
                }
            }

            value = "ford used cars";
            tokens= value.toString().split("\\s+");


            PatternGeneratorKey key1 = new PatternGeneratorKey(0,1,tokens);


             tokens2 = "gm used cars".split("\\s+");
             key2 = new PatternGeneratorKey(0,1,tokens2);

            System.out.println(key1.equals(key2));
            System.out.println(key2.equals(key1));

            System.out.println(key1.hashCode() );
            System.out.println(key2.hashCode() );

            System.out.println(map);

    }

    private static String getPhrase(int l, int i, String[] tokens){

        StringBuffer strin = new StringBuffer();

        int index = 0;
        for(index = i ; index < i+l;index++){
            if(index < i+l-1){
                strin.append(tokens[index]).append("+");
            }
            else
            {
                strin.append(tokens[index]);

            }
        }
        return strin.toString();
    }


}

您的問題是由於equals(PatternGeneratorKey)沒有覆蓋equals(Object) (但它重載了equals(Object) ,因此key1.equals(key2)key1key2PatternGeneratorKey類型的變量時返回true 。) .

由於HashMap調用equals(Object)來檢查鍵是否相等,因此您的方法永遠不會被調用,因此您需要實現equals(Object)

您在 hashCode() 或 equals() 中有一個錯誤。 向我們展示代碼。

大膽猜測:在您的代碼中 key1.equals(key2) 並不意味着 key2.equals(key1)。

您為equals(MyOwnKey)創建了重載,而不是覆蓋equals(Object)

equals()hashCode()上使用@Override注釋。 它將在編譯時捕獲這個相當常見的錯誤。

HashMap#containsKey 覆蓋 AbstractMap#containsKey - 因此條件的方式存在細微差別:

“當且僅當此 map 包含密鑰 k 的映射時才返回 true 使得 (key==null?k==null: key.equals(k))”

被實施。

對於不覆蓋 containsKey() 的 AbstractMap 的子類,那么您很可能只需正確實現 equals() 就可以逃脫。 但是,對於 HashMap,您需要正確執行 hashCode() 並滿足適當的身份。

無論如何 - 向我們展示代碼。

你實際上還沒有實現equals。

公共 boolean 等於(PatternGeneratorKey k){

不是 HashMap 使用的。 它正在尋找公共 boolean 等於( Object obj){}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM