У меня есть реализация хэш-кода для класса, и реализация хэш-кода согласуется с тем, что генерирует eclipse, а также с наиболее распространенной практикой, как обсуждалось здесь
Вот моя реализация хэш-кода (все идентификаторы, используемые в этом методе, составляют ключ для объекта):
public int hashCode() {
final int prime = 31;
int hashCode = 1;
if(uId != null){
hashCode = prime * hashCode + uId.hashCode();
}
if(rId != null){
hashCode = prime * hashCode + rId.hashCode();
}
if(bId != null){
hashCode = prime * hashCode + bId.hashCode();
}
if(reId != null){
hashCode = prime * hashCode + reId.hashCode();
}
if(cId != null){
hashCode = prime * hashCode + cId.hashCode();
}
return hashCode;
}
Я столкнулся со сценарием, когда я тестировал очень большой набор данных, и в моей коллекции не было ожидаемого количества объектов этого класса. При внимательном рассмотрении приведенные ниже два набора данных привели к одному и тому же хэш-коду: 50268236873, и, следовательно, запись была заменена последней, которая была добавлена в коллекцию, поскольку их хэш-коды были одинаковыми.
Existing record :
Record@2c0781cd[uId=54046,rId=10967,bId=177,reId=1728,cId=50194]
Record being inserted into the collection :
Record@20dad050[uId=53806,rId=18389,bId=177,reId=19026,cId=50194]
Both of these had the hashCode value = 50268236873
Итак, вопросы:
1] Это явный случай, когда хэш-коды двух разных объектов имеют одинаковое значение. Так как же гарантировать, что этого не произойдет ни с одним набором данных? Должно ли простое число быть больше?
2] Если мы внимательно посмотрим, переменная hashCode в реализации имеет тип данных int, наибольшее значение которого равно 2^31 - 1 = 2147483647, что больше, чем хэш-код, вычисленный для приведенный выше набор данных = 50268236873, поэтому происходит переполнение. Есть ли какие-либо последствия для использования long в качестве типа значения hashCode?
спасибо
Редактировать :
Я использую HashSet и после прочтения опубликованных ответов я просмотрел реализацию equals, как показано ниже, и я думаю, потому что в equals я проверяю, совпадают ли хэш-коды двух объектов, и использую это, чтобы определить, являются ли они одни и те же объекты приводят к этой проблеме.
Кто-нибудь из вас, ребята, может это подтвердить?
@Override
public boolean equals(Object paramObject) {
boolean equals = false;
if (paramObject != null) {
ACRecord other = (ACRecord) paramObject;
if ((this.hashCode() == other.hashCode()) // I think this is where I am going wrong
|| (this.uId.equals(other.getUId())
&& this.rId.equals(other.getRId())
&& this.reId.equals(other.getReId())
&& this.bId.equals(other.getBId())
&& this.cId.equals(other.getCId))) {
equals = true;
}
}
return equals;
}
Решение. Реализация метода equals была неправильной, так как я использовал hashCode, чтобы определить, равны ли два объекта. Исправление реализации метода equals решило мою проблему, когда hashset заменял существующую запись.
hashCode = prime * hashCode + (id == null ? 0 : id.hashCode());
. В качестве бонуса это облегчает чтение метода. - person Paul Hicks   schedule 20.03.2015if (this.hashCode() != other.hashCode()) { return false; }
, но вы не можете останавливаться на достигнутом. Вы должны проверить равенство без использования hashCode. - person Paul Hicks   schedule 20.03.2015equals
неверна, и вам следует просто избавиться от нее. - person Louis Wasserman   schedule 20.03.2015