再次讨论散列,hashCode()

再次讨论散列,hashCode()

上个文章讲了我们通过hashCode()生成的结果作为桶的下表。从map我们大概看出一点端倪那就是在设计hashCode()时相同的值将产生相同的值。还有就是我们最常用的String具有不变性应该也是通过这种算法实现的(猜的)。如果我们给map中添加值时产生一个hashCode()值,取的时候产生的不同,那不乱套了。但是这个值一但变化就会产生不同的散列码。

此外hashCode依赖于具有唯一性的对象信息,因为hashCode()使用的是对象地址,如果不唯一那产生的值将会混乱保存,这个混论也不知道怎么将,后面有代码,看着代码好理解这个混乱。

想hashCode()实用,那必须快,并且有意义。有意义就是上面讲的基于对象的内容生成散列码。散列码不是独一无二的,但通过hashCode()和equals()可以完全确定对象身份。这是必须的。这又回到上面讲的了,通过hashcode生成桶,equals确定桶中的唯一元素。

好的hashCode()应该产生分布均匀的散列码。如果都集中到一起性能或许还不如线性查找快。

找了一个计算散列码的算法 result = 37 * result +c.后面代码会用到这个算法,当然你也可以自己写个好的。

下面的例子我们通过s和id这俩属性来获取一个桶。再通过这俩域找到对应的值。由于s相同id不同会让其产生不同的散列码,如果只用s大家试试,那么不同的对象可能会产生相同的值。

String不可变性的解释,下面是代码(产生相同的hashcode),有兴趣的自己重写个hashCode自己改变内部算法看看。

public static void main(String[] args) {
        String i = "1";
        String j = "1";
        System.out.println(i.hashCode());//49
        System.out.println(j.hashCode());//49
    }

下面是个加深理解的代码

package a_rongqi.map;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class CountedString {
    private static List<String> created = new ArrayList<String>();
    private String s;
    private int id = 0;
    private CountedString(String str){
        s = str;
        created.add(s);
        for (String s2 : created)
            if (s2.equals(s))
                id++;
    }
    public String toString(){
        return "String" + s + "id:" + id + "hashCode()" + hashCode();
    }
    public int hashCode(){
        int result = 17;
        result = 37 * result + s.hashCode();
        result = 37 * result + id;
        return result;
    }
    public boolean equals(Object o){
        return o instanceof CountedString && s.equals(((CountedString)o).s) && id == ((CountedString)o).id;
    }

    public static void main(String[] args) {
        Map<CountedString,Integer> map = new HashMap<CountedString,Integer>();
        CountedString[] cs = new CountedString[5];
        for (int i = 0;i < cs.length;i++){
            cs[i] = new CountedString("hi");
            map.put(cs[i],1);
        }
        System.out.println(map);
        for (CountedString cstring : cs
             ) {
            System.out.println("Looking up" + cstring);
            System.out.println(map.get(cstring));
        }
    }

}