2012-03-07 2 views
3

У меня есть класс, содержащий коллекцию. Два экземпляра класса равны, если содержимое коллекции равно. Пока я строю свою структуру данных, я храню класс в HashSet, и содержимое коллекции изменяется. Изменения приводят к изменению значения хэш-кода. Это, по-видимому, вызывает побочные эффекты, когда мои данные теряются в наборе. Удаление коллекции из расчета хэш-кода устраняет проблему, но нарушает правило, в котором все поля в equals должны использоваться в хэш-коде.реализация hashcode на java-классах, содержащих коллекции

Как бы вы реализовали hashcode в этой ситуации?

public class LeveZeroHolder 
{ 
private final Set<LevelOneHolder> orgGroups = new HashSet<LevelOneHolder>(); 
private final String name; 

public LeveZeroHolder(String name, LevelOneHolder og) 
{ 
    this.name = name; 
    orgGroups.add(og); 
    og.setFA(this); 
} 

@Override 
public boolean equals(Object obj) 
{ 
    if (this == obj) 
     return true; 
    if (obj == null || obj.getClass() != getClass()) 
     return false; 

    LeveZeroHolder hobj = (LeveZeroHolder)obj; 
    return getOrgGroups().equals(hobj.getOrgGroups()) && getName().equals(hobj.getName()); 
} 

@Override 
public int hashCode() 
{ 
    int rs = 17; 
    rs = rs * 37 + ((getName() == null) ? 0 : getName().hashCode()); 
    rs = rs * 37 + ((getOrgGroups() == null) ? 0 : getOrgGroups().hashCode()); 
    return rs; 
} 

public String getName() 
{ 
    return name; 
} 

public Set<LevelOneHolder> getOrgGroups() 
{ 
    return orgGroups; 
} 

public void addOrgGroup(LevelOneHolder o) 
{ 
    o.setFA(this); 
    orgGroups.add(o); 
} 
} 
+0

Не могли бы вы объяснить свою модель немного больше? Что такое LevelZeroHolder и LevelOneHolder? Хэш-код в идеале не должен меняться на протяжении всего жизненного цикла объекта, поэтому я хотел бы понять, почему эта коллекция находится в вашем хэш-коде, в первую очередь. Нужно ли это быть? – alpian

+3

Что вы подразумеваете под «Это, по-видимому, вызывает побочные эффекты, когда мои данные потеряны»? – assylias

+0

Код выглядит корректно для меня. Я не вижу ничего, что могло бы привести к потере данных при добавлении объекта. –

ответ

5

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

Выписка из Set Javadoc:

Примечание: Большое внимание должно быть осуществлено, если изменяемые объекты используются в качестве набора элементов. Поведение набора не указывается, если значение объекта изменяется таким образом, который влияет на равные сравнения, когда объект является элементом в наборе. Особый случай этого запрета состоит в том, что недопустимо, чтобы набор содержал себя как элемент.

+0

В принципе, вы не можете позволить кому-либо изменять коллекцию после создания объекта, и вам придется перепроектировать код, чтобы компенсировать это. Используйте 'Collections.unmodifiableXXX' или Guba' ImmutableXXX' для обеспечения неумолимости. –

+0

Так как мне нравится играть с огнем, и у меня нет времени полностью перепроектировать, я решил удалить объект, который будет изменен, и повторно добавить после модификации. – Aaron

0

Если ваша коллекция LevelOneHolder действительно влияет на уникальность вашего объекта, то вы должны сделать LevelZeroHolder неизменным. Если вы добавите LevelOneHolder в свой LevelZeroHolder, вы должны вместо обновления коллекции вернуть совершенно новый LevelZeroHolder с коллекцией, скопированной из уже существующей, и присоединиться к новой, которую вы хотите добавить.

Таким образом, hashCode никогда не изменяется, но вы получаете разные LevelZeroHolders с различными хэш-кодами. Вероятно, это правильно, хотя вы считаете, что вложенная коллекция в LevelZeroHolder способствует уникальности этого объекта.

0

Если вы поместите свой объект в структуру данных, где вы зависеть от hashCode или equals(), чтобы найти его, И если вы измените какое-либо свойство объекта (например, его имя или что-то в его списке) когда он уже находится в этой структуре данных, вы не найдете его. Это ваш случай?

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

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

Попробуйте вместо этого использовать неизменяемые объекты.

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