看如下程序 我感觉a1和a2是相等的(equals方法已经被覆盖) 但是HashSet添加时把“相同值”添加进去了 搞不懂为什么 求大神解释
import java.util.HashSet;class A {    private int id;    public A(int id) { this.id = id; }    //若两A对象id相同则返回true    @Override public boolean equals(Object obj) {        if(obj instanceof A)            return id == ((A) obj).id;        return false;    }    @Override public String toString() {        return id + "";    }}public class Confusion {    public static void main(String[] args) {        A a1 = new A(1);        A a2 = new A(1);        A a3 = new A(2);        HashSet<A> a = new HashSet<A>();        a.add(a3);        a.add(a2);        a.add(a1);        System.out.println(a);        //我感觉结果应该是[1,2]或[2,1] 但是结果是[1,2,1] ????​    }}

解决方案 »

  1.   

    class A { private int id; public A(int id) {
    this.id = id;
    } @Override
    public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + id;
    return result;
    }
    @Override
    public boolean equals(Object obj) {
    if (this == obj)
    return true;
    if (obj == null)
    return false;
    if (getClass() != obj.getClass())
    return false;
    A other = (A) obj;
    if (id != other.id)
    return false;
    return true;
    } @Override
    public String toString() { return id + ""; }}public class Confusion { public static void main(String[] args) { A a1 = new A(1); A a2 = new A(1); A a3 = new A(2); HashSet<A> a = new HashSet<A>(); a.add(a3); a.add(a2); a.add(a1);
    System.out.println(a1.equals(a2));
    System.out.println(a); }}还要重写下hashcode才行
      

  2.   

    就象楼上说的,必需重写hashCode()方法和equals()方法。
      

  3.   


    在set类型的集合中,如何判断元素是否重复呢,这就需要使用Object.equals方法,但如果元素很多了,添加一个新元素时,比较的次数 就很多,例如已经有100个元素了,添加第101个元素时,就要和前面的元素比较100次,效率很低。   JAVA中采用哈希表的原理,哈希算法也称为散列算法,是将数据依据算法直接指定到一个地址上,  hascode实际上是返回的对象存储的物理地址   HashSet类按照哈希算法来存取对象,当向集合中加入一个新对象时,会调用对象的HashCode()方法得到对象的哈希码,然后根据这个码计算出对象在集合中存储的位置。   Object类中定义了hashCode()和equals(Object o)方法,如果object1.equals(object2),那么说明这两个引用变量指向同一个对象,那么object1 and object2的hashCode也一定相等   为了保证HashSet能正常工作,要求当两个对象用equals比较相等时,hashCode也要相等,否则就会有可能加入两个相同的项。
      

  4.   

    这句话不对吧,hashcode 怎么可能和存储地址有关系? 这东西可以人为设定。
      

  5.   

    o~我明白你的意思了,你说的是在set容器里的位置。
      

  6.   

    必需重写hashCode()方法和equals()方法。
      

  7.   

    直接看源码HashSet的add方法,内部通过一个map来实现不重复public boolean add(E e) {
        return map.put(e, PRESENT)==null;
    }HashMap的put方法:public V put(K key, V value) {
            if (key == null)
                return putForNullKey(value);
            int hash = hash(key.hashCode());//使用hashCode来找存放位置,楼主没有改写hashCode方法所以原来值没有被覆盖掉。
            int i = indexFor(hash, table.length);
            for (Entry<K,V> e = table[i]; e != null; e = e.next) {
                Object k;
                if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
                    V oldValue = e.value;
                    e.value = value;
                    e.recordAccess(this);
                    return oldValue;
                }
            }        modCount++;
            addEntry(hash, key, value, i);
            return null;
        }Effective java中建议我们改写equals方法的时候一定要改写hashCode方法,否则在使用某些集合的时候会影响功能。
      

  8.   

    楼主定义的equals方法是不是有点错误啊?
    return语句少else吧
      

  9.   

    不错,哈希可以用来高效定位,哈希值作为index可以直接定位bucket,bucket可以是链表形式,存储碰撞的同哈希值元素。
      

  10.   

    这种写法,实质上只是判断了a1和a3的指向的对内存地址值不一样,所以添加了,但是如果重写了hashcode方法后,会发现他们指向的1在常量池里面的地址值是一样的,就不会添加了