2015-02-15 2 views
2

Представьте себе следующую задачу:Java hashCode, искусственные поля?

// Class PhoneNumber implements hashCode() and equals() 
PhoneNumber obj = new PhoneNumber("mgm", "089/358680"); 
System.out.println("Hashcode: " + 
    obj.hashCode()); //prints "1476725853" 

// Add PhoneNumber object to HashSet 
Set<PhoneNumber> set = new HashSet(); 
set.add(obj); 

// Modify object after it has been inserted 
obj.setNumber("089/358680-0"); 

// Modification causes a different hash value 
System.out.println("New hashcode: " + 
    obj.hashCode()); //prints "7130851" 

// ... Later or in another class, code such as the following 
// is operating on the Set: 

// Unexpected Result! 
// Output: obj is set member: FALSE 
System.out.println("obj is set member: " + 
    set.contains(obj)); 

Если у меня есть класс, и я хочу, чтобы все мои поля, чтобы быть редактируемыми и все еще быть в состоянии использовать набор/хэш-код. Было бы хорошей идеей создать искусственное неизменяемое поле в классе, установленном при создании объекта? Например, текущее время в мс. Когда у меня есть это поле, я могу создать хэш-код, и я все равно смогу редактировать все «реальные» поля. Будет ли это хорошей идеей?

+0

Только если это имеет смысл.Как вы собираетесь посмотреть что-то в наборе на основе «искусственного» поля? –

+0

, конечно, это называется «инкапсуляция данных»: https://en.wikipedia.org/wiki/Data_encapsulation – specializt

+0

Время в миллисе не так много, но, возможно, GUID. –

ответ

3

Я твердо верю, что вы представляете плохой вариант использования: если вам нужно изменить объект в Set, вы обязательно должны удалить старый и снова добавить новый (или использовать другой java.util.Collection). Принимая из вашего примера:

Set<PhoneNumber> set = new HashSet(); 
set.add(obj); 

// Modify object after it has been inserted 
set.remove(obj); 
obj.setNumber("089/358680-0"); 
set.add(obj); 

Вся цель hashCode заключается в создании ведро подобных объектов, чтобы уменьшить пространство поиска, поэтому оно должно быть неизменным, но полезно для вас (если вы используете искусственное поле, как вы обнаружите объект в своем наборе позже? Как вы извлекаете это искусственное поле, если вы не используете хранилище постоянного хранения любого типа - идентификатор в базе данных является исключением в использовании искусственного поля IMHO).

Чтобы объяснить смысл

Вся цель hashCode заключается в создании ведро подобных объектов, чтобы уменьшить пространство поиска

взглянуть на этот образец кода: http://ideone.com/MJ2MQT. I (ошибочно), созданный для объектов с одним и тем же хеш-кодом, а затем добавил оба к набору; как и ожидалось, набор содержит оба из них, потому что хэш-код используется для извлечения элементов, которые сталкиваются, а затем вызывается метод equals для решения этого столкновения. Столкновения (см. different objects which return same hash code) неизбежны, и цель надлежащей конкретизированной функции хэш-кода состоит в том, чтобы уменьшить их как можно больше.

0

Как правило, имеет смысл иметь уникальный идентификатор для ваших объектов данных, особенно если вы сохраняете их в некоторой базе данных. Это позволит вам легко реализовать equals и hashCode, которые будут зависеть только от этого единственного идентификатора.

Я не уверен, что текущее время в мс. будет лучшим выбором, но вы обязательно должны создать уникальный идентификатор.

+2

Хотя я согласен с уникальным идентификатором для баз данных, я склонен не соглашаться, если это хороший подход к тому, что делает OP. Тот факт, что он использует 'Set', заставляет меня чувствовать, что он ожидает дублирования объектов и хочет сохранить только уникальные. Basing hashCode (и, следовательно, равно) по уникальным идентификаторам гарантирует, что ни один из двух объектов не будет одинаковыми полями, даже если они имеют идентичный реальный контент. – SuperSaiyan

+0

@Thrustmaster Это зависит от того, когда генерируется уникальный идентификатор. Если он генерируется только при создании нового объекта (в отличие от существующего объекта, загружаемого из БД или из какого-либо другого постоянного хранилища), это будет иметь смысл. Если, с другой стороны, он генерируется для любого нового экземпляра класса, это не имеет никакого смысла, поскольку в этом случае вы можете просто использовать стандартную реализацию равных (==) и hashCode объекта. – Eran

+0

Да, именно поэтому я согласился с вами в части базы данных. Что касается поставленного вопроса, то вообще не упоминается база данных. Что касается второй части вашего комментария, OP все равно придется переопределять equals() и hashCode() и не может использовать реализацию по умолчанию Object. – SuperSaiyan

1

Сохранение измененных объектов в хэш-наборе или использование их в качестве ключей в хэш-карте, безусловно, является не хорошей идеей, именно по той причине, что вы проиллюстрируете в своем коде.

С другой стороны, определение искусственного числа, которое служит в качестве объекта ID, приводит к победе над целью иметь хэш-код в первую очередь, поскольку он не помогает найти объект, путем ограничения поиска объектов с идентичными хэш-кодами.

Фактически, ваше решение не отличается от построения Map<Integer,PhoneNumber> от «искусственного хеш-кода» к вашему изменяемому объекту PhoneNumber. Если поиск объектов по ассоциации - это то, что вам нужно, HashMap от искусственного идентификатора к изменяемому объекту - это путь.

Смежные вопросы