import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class Test
{
 public static void main(String[] args)
 {
  Set<Element> set = new HashSet<Element>();
  Element i1 = new Element(1);
  Element i2 = new Element(2);
  Element i3 = new Element(3);
  set.add(i1);
  set.add(i2);
  set.add(i3);
  System.out.println("Before changed:");
  printSet(set);
  i1.setValue(2);
  System.out.println(i1.equals(i2));
  System.out.println("After changed:");
  printSet(set);
 }
 public static void printSet(Set set)
 {
  Iterator it = set.iterator();
  while (it.hasNext())
  {
   System.out.println(it.next());
  }
 }
}
class Element
{
 private int value;
 public Element(int value)
 {
  this.value = value;
 }
 public void setValue(int value)
 {
  this.value = value;
 }
 public int getValue()
 {
  return this.value;
 }
 @Override
 public String toString()
 {
  return "" + this.value;
 }
 @Override
 public boolean equals(Object obj)
 {
  if(this ==(Element)obj)
   return true;
  if (!(obj instanceof Element))
  {
   return false;
  }
  if (((Element) obj).getValue() == this.getValue())
  {
   return true;
  }
  return false;
 }
 @Override
 public int hashCode()
 {
  return 37 + this.value;
 }
}
在网上看到这个程序,这种先增加再修改的方法导致set有重复元素,是否违背了set的设计初衷呢

解决方案 »

  1.   

    System.out.println("After remove");
    set.remove(i1);
    printSet(set);
    System.out.println("After add again");
    set.add(i1);
    printSet(set);竟然还可以重新添加,迷茫too....After remove
    2, hashCode=39
    3, hashCode=40
    After add again
    2, hashCode=39
    2, hashCode=39
    3, hashCode=40
      

  2.   

    我怎么觉得他这是生成了3个不同的对象
    只是这三个对象中的一个属性(value)的值有一样
    然后他又重载了equals和hashCode方法
    让equals方法打印出来的值为true来欺骗观众
    ………………
    而已…………
      

  3.   

    纯粹是不看API乱写代码:看看Object类的hashCode的说明,不按说明来当然就乱套了!
    以下摘自javaAPI java.lang.Object的hashCode方法说明:hashCode
    public int hashCode()返回该对象的哈希码值。支持该方法是为哈希表提供一些优点,例如,java.util.Hashtable 提供的哈希表。 
    hashCode 的常规协定是: 在 Java 应用程序执行期间,在同一对象上多次调用 hashCode 方法时,必须一致地返回相同的整数,前提是对象上 equals 比较中所用的信息没有被修改。从某一应用程序的一次执行到同一应用程序的另一次执行,该整数无需保持一致。 
    如果根据 equals(Object) 方法,两个对象是相等的,那么在两个对象中的每个对象上调用 hashCode 方法都必须生成相同的整数结果。 
    以下情况不 是必需的:如果根据 equals(java.lang.Object) 方法,两个对象不相等,那么在两个对象中的任一对象上调用 hashCode 方法必定会生成不同的整数结果。但是,程序员应该知道,为不相等的对象生成不同整数结果可以提高哈希表的性能。 
    实际上,由 Object 类定义的 hashCode 方法确实会针对不同的对象返回不同的整数。(这一般是通过将该对象的内部地址转换成一个整数来实现的,但是 JavaTM 编程语言不需要这种实现技巧。) 
    返回:
    此对象的一个哈希码值。
    另请参见:
    equals(java.lang.Object), Hashtable这个Element遵守了hashCode的规范了吗?
      

  4.   

    同样,equals方法也是需要遵守规范的,否则会出现莫名其妙的问题:equals
    public boolean equals(Object obj)指示某个其他对象是否与此对象“相等”。 
    equals 方法在非空对象引用上实现相等关系: 自反性:对于任何非空引用值 x,x.equals(x) 都应返回 true。 
    对称性:对于任何非空引用值 x 和 y,当且仅当 y.equals(x) 返回 true 时,x.equals(y) 才应返回 true。 
    传递性:对于任何非空引用值 x、y 和 z,如果 x.equals(y) 返回 true,并且 y.equals(z) 返回 true,那么 x.equals(z) 应返回 true。 
    一致性:对于任何非空引用值 x 和 y,多次调用 x.equals(y) 始终返回 true 或始终返回 false,前提是对象上 equals 比较中所用的信息没有被修改。 
    对于任何非空引用值 x,x.equals(null) 都应返回 false。 
    Object 类的 equals 方法实现对象上差别可能性最大的相等关系;即,对于任何非空引用值 x 和 y,当且仅当 x 和 y 引用同一个对象时,此方法才返回 true(x == y 具有值 true)。 注意:当此方法被重写时,通常有必要重写 hashCode 方法,以维护 hashCode 方法的常规协定,该协定声明相等对象必须具有相等的哈希码。 
    参数:
    obj - 要与之比较的引用对象。 
    返回:
    如果此对象与 obj 参数相同,则返回 true;否则返回 false。
    另请参见:
    hashCode(), Hashtable
      

  5.   

    比如在HashSet中,可以添加重复的元素,但是添加之后,HashSet的功能就失效了,不能用hashCode去查找到对应的值了。
    我觉得这是从概念上说,不能加,实际加了会破坏Set的概念。
      

  6.   

    首先我不认为,这个反面的用例在瞎搞;相反我认为这个是对hashSet内部实现的比较了解的
    基础上,对set规则的刻意破坏。set在添加元素时,依赖hashCode,
    Equals两个函数的返回值。而楼主的用例,是在元素添加set以后,刻意去修还元素的数字以达到
    修改hashCode,equals返回值,这是set出现“重复”也是自然的了。简单的说,set只在加入是会
    检查数据的重复性,加入后就不管了(其实set也管不了)。
      

  7.   

    我认为不是equals和hashCode错误,而是调了i1.setValue(2);。Trust me.
      

  8.   

    ticmy你叫的很多,但其实反而证明了你不懂hashcode,equals。
    楼主的例子里的hashcode和equals是没问题的。
      

  9.   

    这个接口的API文档说的多好:Note: Great care must be exercised if mutable objects are used as set elements. The behavior of a set is not specified if the value of an object is changed in a manner that affects equals comparisons while the object is an element in the set.
      

  10.   


    Oracle
      

  11.   

    脑残好多啊。
    Set只在add的时候保证唯一性,你add进来后再改Set就管不了了。
    也就是说,Set中是可以存在非唯一性的情况的。
    当然,正常情况下我们要避免add进来后再修改对象的值。
      

  12.   

    Set 集合是不允许重复的,估计地球人都知道,可是他是怎么算出重复数据并且不添加到集合里的呢?就有不少人不了解了。Set 集合重复与否主要依赖于hashcode与equals,估计也是地球人都知道的。Set 集合在add 的时候到底做了什么事呢?Set 集合在add 时,就会先去执行添加进行来的对像的hashcode方法。然后再去这个Set集合里找这个hashcode这个码是否存在这个Set集合地址中,如果存在那么就调用这个对像的equals去处理,equals返回false表示不是同个对像,前面说了在地址中存在了,但equals是false。所以这个对像照样添加天set。
    如果这个equlas返回true,那个Set集合就认为。这是同一个对像。不加进行添加操作。如果hashcode这个码不存在这个Set集合地址中。则直接添加到Set .而不进行equals操作。所以得出一个结论:
      有相同hashcode的对像。可以存放在一个Set中,有相同equals的对像不能存放在同一个Set中。
      

  13.   

    最后是用element.value 比较两个对象
    set保证没有相同的对象 但是不能保证 没有2个拥有相同属性值的对象吧
    坐等高人解答
      

  14.   

    22楼你说了这么多,你看楼主的代码了吗?
    add进来的时候是不等的,我add进来再把其中的一个值改成等于另一个值。懂了吗?
      

  15.   

    15F 引用的原文已經說明了原因。這裡補充一點,所謂不重複應該指的是可識別的資料,有 ID 的隱含意義,
    所以這種資料不應該是可修改的。
    因此修改ID造成物件重複,應該算是設計產生的 bug。最後回到原問題 set中真的不能添加重复元素吗?
    的確不能"添加"重複元素,但可以"修改"元素使其重複。
      

  16.   

    Set是无序不重复,List是有序重复
    可以使用Set x = new HashSet(listInstance);的方式将有序重复的List转为无序不重复的~
    反之却不怎么能~~
      

  17.   

    “return 37 + this.value;”
    这样的hashCode还没有问题javaAPI的描述是hashCode在一次运行中值是不应该改变的,而这个value是个动态值,显然是不按协定来
      

  18.   

    是的 set 不能重复.   list可以重复
    set 乱序  list是顺序
      

  19.   

    set 只是在 添加元素的时候会去做equals.   当里面的元素发生了变化,是不监视的
      

  20.   


    我敢说你从来没有自己写过hashcode()方法,也根本不知道hashcode的意义。
    自定义类的hashcode()就是要使用值而不是使用地址,这样才能真正的判断值的相等性而不是地址的相等性。懂?
      

  21.   

    List动态集合的接口,好处是可以动态添加元素。很方便的通过Itractor迭代器来遍历集合元素。
    Map是键值对形式的集合,好处是可以通过相应键找到相应的值,就好比一把钥匙开一把相应的锁。
    set也是一种集合,其相邻的两个元素之间的有关系机制,好处是方便的横向的搜索相邻集合元素,但一旦删除其中的一个元素,则其相邻元素关系就得变更,不方便动态的添加和删除元素。
      

  22.   


    在同一对象上多次调用 hashCode 方法时,必须一致地返回相同的整数,前提是对象上 equals 比较中所用的信息没有被修改。看懂前提了吗?
    你的发言暴露了你从来没有写过hashcode的真相。