Пользовательский универсальный класс как ключ к проблеме с хэш-картой - PullRequest
0 голосов
/ 20 февраля 2011

У меня есть следующий тестовый код:

public static final String[] list = {
    "apple","ball","cat","dog","egg","fan","girl","hat","igloo","jerk"  
};

...

HashMap<DoubleKey<Integer, Integer>, String> hm = new HashMap<DoubleKey<Integer, Integer>, String>();
Set<DoubleKey<Integer, Integer>> s = new TreeSet<DoubleKey<Integer, Integer>>();
Random g = new Random();
for(int i=0; i<10; i++){
    int first = g.nextInt(9999) + 1000; 
    int second = g.nextInt(9999) + 1000; 
    DoubleKey<Integer, Integer> k1 = new DoubleKey<Integer, Integer>(first, second);
    DoubleKey<Integer, Integer> k2 = new DoubleKey<Integer, Integer>(first, second);
    s.add(k1);
    hm.put(k2, list[i]);
}

Set<DoubleKey<Integer, Integer>> ts = hm.keySet();
Iterator<DoubleKey<Integer, Integer>> itr = ts.iterator();
while(itr.hasNext()){
    DoubleKey<Integer, Integer> k = itr.next(); 
    System.out.println(k.getFirstKey().toString() + " + " + k.getSecondKey().toString() + " -> " + hm.get(k).toString());
}

System.out.println("----");
Iterator<DoubleKey<Integer, Integer>> sItr = s.iterator();
while(sItr.hasNext()){
    DoubleKey<Integer, Integer> k = sItr.next();
    String currStr = hm.get(k);
    System.out.println(k.getFirstKey().toString() + " + " + k.getSecondKey().toString() + " -> " + currStr);
}

Что я сделал, это создал Custom Generic Class DoubleKeyсодержать ключ, состоящий из двух частей.Как видите, Set s и ключи HashMap hm имеют одинаковые компоненты, но были созданы по-разному ( k1 = k2 ).Когда я пытаюсь получить значение с помощью клавиш от s до хм , возвращается ноль , хотя при первой печати оно показываетправильное отображение.

Sample Output:

3922 + 2544 -> girl
9267 + 3750 -> hat
3107 + 10929 -> apple
5162 + 8834 -> fan
8786 + 1125 -> cat
10650 + 4078 -> egg
3808 + 7363 -> jerk
1364 + 7657 -> dog
1364 + 4412 -> ball
1583 + 1460 -> igloo
----
10650 + 4078 -> null
1364 + 4412 -> null
1364 + 7657 -> null
1583 + 1460 -> null
3107 + 10929 -> null
3808 + 7363 -> null
3922 + 2544 -> null
5162 + 8834 -> null
8786 + 1125 -> null
9267 + 3750 -> null

Это моя реализация DoubleKey:

public class DoubleKey<K extends Comparable<K>,J extends Comparable<J>> implements Comparable<DoubleKey<K,J>>{

    private K key1;
    private J key2;

    public DoubleKey(K key1, J key2){
        this.key1 = key1;
        this.key2 = key2;
    } 

    public K getFirstKey(){
        return this.key1;
    }

    public J getSecondKey(){
        return this.key2;
    }

    // need for Comparable interface
    public int compareTo(DoubleKey<K,J> aThat){
        // NOTE: check for nulls
        return (this.key1.toString() + this.key2.toString()).compareTo(aThat.key1.toString() + aThat.key2.toString());
    }

    public boolean equals(DoubleKey<K,J> aThat){
        return (this.key1.toString() + this.key2.toString()).equals(aThat.key1.toString() + aThat.key2.toString());
    }

}

Как это произошло?Могут ли два объекта (в данном случае из настраиваемого универсального) отличаться от eve3n, если они созданы с двумя одинаковыми значениями?Как я могу это исправить?Я надеюсь, что кто-то может помочь мне здесь.Спасибо!

Ответы [ 3 ]

4 голосов
/ 20 февраля 2011

В дополнение к .hashCode() у вас должна быть реализация equals(Object), а не (только) equals(DoubleKey<...>), так как в противном случае у вас будет два независимых метода (и только первый действительно вызывается из HashMap) , Вот предложение:

public boolean equals(Object other) {
    if(this == other)
       return true;
    if(!(other instanceof DoubleKey))
       return false;
    DoubleKey that = (DoubleKey)other;
    return (this.key1 == null ? that.key1 == null : this.key1.equals(that.key1)) &&
           (this.key2 == null ? that.key2 == null : this.key2.equals(that.key2));
}

Метод hashCode также должен соответствовать этому, например, так:

public int hashCode() {
    return key1.hashCode() * 3 + key2.hashCode() * 5;
}

Ваше сравнение key1.toString()+key2.toString() немного опасно, поскольку оно позволяет (1, 21).equals((12,1)) быть правдой, что обычно не предназначено. То же самое верно для вашего метода compareTo - сравнивайте компоненты, используя их метод compareTo, а не объединенную строку.

3 голосов
/ 20 февраля 2011

Выучите этот урок сейчас: если вы переопределяете метод equals (как вы это сделали), то вы ДОЛЖНЫ также переопределить метод хэш-кода. Этот метод используется для различных целей, включая поиск элементов в HashMaps.

1 голос
/ 20 февраля 2011

Где переопределение метода hashCode класса DoubleKey?Я не думаю, что он будет работать как правильный ключ, если вы не реализуете это, потому что иначе ваши два объекта будут считаться разными.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...