A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 尹善波 中级黑马   /  2012-8-5 10:00  /  1257 人查看  /  2 人回复  /   1 人收藏 转载请遵从CC协议 禁止商业使用本文

//简化HashSet
import java.util.*;
class HashSetTest
{
public static void sop(Object obj)
{
  System.out.println(obj);
}
public static void main(String[] args)
{
  HashSet hs = new HashSet();
    hs.add(new Person("a1",11));//集合每次添加对象都会是自动调用hashCode和equals方法,这是在覆写hashSet的内部方法吗?
                                //能不能详细解释一下这其中的原理

  int x=hs.hashCode( );//获取集合的哈希值,
  sop("x....."+x);//可是根据结果看a1怎么被加载两次呢?

      hs.add(new Person("a2", 11));
   hs.add(new Person("a3",13));
   int x1=hs.hashCode( );//同样是获取哈希值,这个结果更令人费解了,结果在下面,这是怎么回事?
  sop("x1...."+x1);
     hs.add(new Person("a2",11));
  sop(hs.add(new Person("a4",14)));

}
}
class Person
{
private String name;
private int age;
Person(String name,int age)
{
  this.name = name;
  this.age = age;
}
public int hashCode ()
{
  System.out.println(this.name+"....hashCode");
  return name.hashCode()+age*37;  
}
public boolean equals(Object obj)
{
  if(!(obj instanceof Person))
   return false;
  Person p = (Person)obj;
  System.out.println(this.name+"...equals.."+p.name);
  return this.name.equals(p.name) && this.age == p.age;
}

}
/*
E:\java\edit>java  HashSetTest
a1....hashCode
a1....hashCode
x.....3463
a2....hashCode
a3....hashCode
a1....hashCode
a3....hashCode
a2....hashCode
x1....10466
a2....hashCode
a2...equals..a2
a4....hashCode
true

*/

评分

参与人数 1技术分 +1 收起 理由
张立江 + 1 赞一个!

查看全部评分

2 个回复

倒序浏览
1,这不是复写hashSet里面的方法,而是复写Object里面的方法。
2,为什么会被打印两次,我认为可能是在算集合的hashcode值时候,需要计算出里面所存的对象的hashcode值,这是第二次,第一次就是正常的调用。
3,hashCode值,应该根据集合里面存储的对象元素所计算出来的。所以不一样也没什么奇怪的。
以上是我个人见解,希望是对的

评分

参与人数 1技术分 +1 收起 理由
张立江 + 1 很给力!

查看全部评分

回复 使用道具 举报
其实,你可以看一下JAVA里面关于HashSet的源代码,就能够理解里面的原理了:
hs.add(new Person("a1",11));    在HashSet的源代码里是这样的:
public boolean add(E e) {
        return map.put(e, PRESENT)==null;
    }
其中map是HashSet内部的一个HashMap,接着看
public V put(K key, V value) {
        if (key == null)
            return putForNullKey(value);
        int hash = hash(key.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;
    }
其中就有int hash = hash(key.hashCode());和if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
里面明确调用了Person里的hashCode和equals的方法。
所以hs.add(new Person("a1",11));打印第一句a1....hashCode
下面int x=hs.hashCode( ); 在HashSet的源代码里是这样的:
public int hashCode() {
        int h = 0;
        Iterator<E> i = iterator();
        while (i.hasNext()) {
            E obj = i.next();
            if (obj != null)
                h += obj.hashCode();
        }
        return h;
    }
里面(h += obj.hashCode();)迭代调用了元素中的hashCode方法。
所以出现了第二句的a1....hashCode
同理hs.add(new Person("a2", 11));打印出a2....hashCode
hs.add(new Person("a3",13));打印出a3....hashCode
int x1=hs.hashCode( );迭代打印出a1....hashCode
a3....hashCode
a2....hashCode
因为hashCode的排列是按哈希的顺序,所以打印次序是这样的
hs.add(new Person("a2",11));打印出a2....hashCode
上文已经提到int hash = hash(key.hashCode());和if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
里面明确调用了Person里的hashCode和equals的方法。
所以也打印出a2...equals..a2
hs.add(new Person("a4",14));打印出a4....hashCode
因为public boolean add(E e) {
        return map.put(e, PRESENT)==null;
    }
是有返回值的,所以打印出true

评分

参与人数 1技术分 +1 收起 理由
张立江 + 1 后半段解答的很详细,非常不错.

查看全部评分

回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马