Я выполнил свой класс с несколькими ключами следующим образом:
public class ProbabilityIndex {
private int trueLabel;
private int classifiedLabel;
private int classifierIndex;
public ProbabilityIndex(int trueLabel, int classifiedLabel, int classifierIndex) {
this.trueLabel = trueLabel;
this.classifiedLabel = classifiedLabel;
this.classifierIndex = classifierIndex;
}
@Override
public boolean equals(Object obj) {
if ( !obj instanceof ProbabilityIndex)
return false;
if (obj == this)
return true;
ProbabilityIndex rhs = (ProbabilityIndex) obj;
return new EqualsBuilder().
append(trueLabel, rhs.trueLabel).
append(classifiedLabel, rhs.classifiedLabel).
append(classifierIndex, rhs.classifierIndex).
isEquals();
}
@Override
public int hashCode() {
int hashCode = new HashCodeBuilder(17, 31).
append(trueLabel).
append(classifiedLabel).
append(classifierIndex).
toHashCode();
return hashCode;
}
}
Обратите внимание на то, что trueLabel
, classifiedLabel
и classifierIndex
все 0 или 1.
Затем я использую свой ключ следующим образом:
ProbabilityIndex key = new ProbabilityIndex(trueLabel, classifiedLabel, classifierIndex);
probabilities.put(key, new Double(value));
где probabilities
объявляются следующим образом:
HashMap<ProbabilityIndex, Double> probabilities;
Тем не менее, различные комбинации trueLabel
, classifiedLabel
и classifierIndex
написать кортеж в том же самом положении в probabilities
, таким образом, перезаписи существующих кортежей.
Как я могу решить эту проблему?
Минимальный тестовый пример:
HashMap<ProbabilityIndex, Double> map = new HashMap<ProbabilityIndex, Double>();
map.put(new ProbabilityIndex(0, 0, 0), new Double(0.1));
map.put(new ProbabilityIndex(0, 0, 1), new Double(0.2));
map.put(new ProbabilityIndex(0, 1, 0), new Double(0.1));
map.put(new ProbabilityIndex(0, 1, 1), new Double(0.2));
map.put(new ProbabilityIndex(1, 0, 0), new Double(0.1));
Это добавляет 4 кортежа вместо 5.
Я могу только сказать вам, что хэш-таблица никогда не будет перезаписывать объекты с одним и тем же хэш-кодом (хеш-столкновение); это будет менее эффективным в их поиске.
Единственный способ, чтобы ваши записи были неправильно перезаписаны, - это предоставить метод equals
для ключа, который возвращает true
для разных ключей.
Несколько дополнительных советов, не связанных напрямую с вашей проблемой: если все, что у вас есть, это три переменные с двумя состояниями, то полное значение, установленное для класса, имеет мощность всего 8. Вместо сложного построителя хеш-кода, который вы используете, вы могли бы просто построить хэш-код с тремя битами, каждый из которых представляет одну переменную. Это явно гарантирует, что каждое состояние вашего объекта имеет отличный хеш-код.
Я проверил ваш код со следующими реализациями hashCode()
и equals()
(мне пришлось изменить equals
чтобы ваш пример действительно был автономным):
@Override public boolean equals(Object obj) {
if (!(obj instanceof ProbabilityIndex)) return false;
if (obj == this) return true;
ProbabilityIndex rhs = (ProbabilityIndex) obj;
return this.trueLabel == rhs.trueLabel
&& this.classifiedLabel == rhs.classifiedLabel
&& this.classifierIndex == rhs.classifierIndex;
}
@Override public int hashCode() {
return trueLabel | (classifiedLabel << 1) | (classifierIndex << 2);
}
В результате вашего тестового кода появилась карта с пятью записями.
В качестве окончательной заметки вам даже не нужна хэш-таблица, если ее максимальный размер будет равен 8. Простой массив размером 8, индексированный указанным хэш-кодом, будет достаточным.
public int hashCode() { return 1; }