2011-04-27 28 views
3

所以,我做了在Java中我自己的組合鍵與3名關鍵一個HashMap中沒有發現用於複合對象

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(); 
    } 


} 
+0

toEquals?比較?希望這只是錯別字。 – MeBigFatGuy 2011-04-27 17:29:03

+2

問題可能是equals和hashcode的實現。發佈它們會非常有幫助。 – Affe 2011-04-27 17:30:03

+0

我們可以看到MyOwnKey類的完整版本,或至少計算哈希碼和等於等的部分嗎?另外,爲什麼這兩個鍵應該相等? – 2011-04-27 17:31:59

回答

4

您的問題是由事實equals(PatternGeneratorKey)不會覆蓋equals(Object)引起的(但重載equals(Object),使key1.equals(key2)回報truekey1key2PatternGeneratorKey類型的變量!)。

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

+0

謝謝! http://stackoverflow.com/questions/185937/overriding-the-java-equals-method-quirk – 2011-04-27 18:02:08

+2

很棒!如果您始終記得將@Override註釋添加到「所謂的」擴展方法中,則可以在編譯時捕獲這些問題。 – 2011-04-27 18:03:24

2

測試代碼,您在任的hashCode()還是equals()有一個bug。向我們展示代碼。

狂猜:在你的代碼中key1.equals(key2)並不意味着key2.equals(key1)。

+0

key2.equals(key1)也返回true。 – 2011-04-27 17:40:04

1

的HashMap#中的containsKey覆蓋AbstractMap#中的containsKey - 所以有一個在路上一個微妙的差異的情況:當且僅當此映射包含鍵k使得映射

「返回true(鍵== null?k == null:key.equals(k))「

被實現。

對於不覆蓋containsKey()的AbstractMap的子類,那麼你可能很容易就能正確實現equals()。但是,對於HashMap,您需要具有正確的hashCode()實現並滿足適當的標識。

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

1

你實際上沒有實現equals。

公共布爾等於(PatternGeneratorKey K){

是不是有什麼HashMap的使用。它尋找公共布爾等於(對象 OBJ){}

2

您創建了一個超載equals(MyOwnKey),而不是覆蓋equals(Object)

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

相關問題