zoukankan      html  css  js  c++  java
  • Java集合(7):散列与散列码

           散列的价值在于速度。我们使用数组来保存键的信息,这个信息并不是键本身,而是通过键对象生成一个数字(散列码),作为数组下标。由于数组的容量是固定的,而散列容器的大小是可变的,所以不同的键可以产生相同的数组下标(散列码)。也就是说,可能会有冲突(当然也有特例,比如EnumMap和EnumSet)。所以,数组的值存放着一个保存所有相同散列码的值的list(引用)。然后对list中的值使用equals进行线性查询。如果散列函数设计的比较好的话,数组的每个位置只有较少的值,并且浪费空间也小。于是,查询过程就是首先计算键的散列码得到数组下标,然后内存寻址(时间复杂度为O(1),赋值)找到数组的值,再遍历list(时间复杂度为O(n),线性查询)即可。即hashCode和equals共同确定了对象的唯一性。

           所有类都继承于Object。Object的hashCode方法生成的散列码,实际上是默认使用对象的地址计算散列码;而Object的equals方法实际上就是地址比较(==)。显然,当我们在使用散列容器(如HashMap的Key,HashSet等)时,我们自定义的类中还继承Object的hashCode和equals是不行的。必须重写hashCode和equals方法。好的hashCode()应该产生分布均匀的散列码。可以用IDE自动生成。下面是一个例子:

     1 import java.util.List;
     2 
     3 public class Test9 {
     4 
     5     boolean a;
     6     byte b;
     7     short c;
     8     int d;
     9     char e;
    10     long f;
    11     float g;
    12     double h;
    13     String i;
    14     List<String> j;
    15     int[] k;
    16 
    17     @Override
    18     public int hashCode() {
    19         // [STEP1] hashCode()里的魔法数字,之所以选择31,是因为它是个奇素数,如果乘数是偶数,并且乘法溢出的话,信息就会丢失,因为与2相乘等价于移位运算。
    20         // 使用素数的好处并不是很明显,但是习惯上都使用素数来计算散列结果。31有个很好的特性,就是用移位和减法来代替乘法,可以得到更好的性能:31*i==(i<<5)-i。现在的VM可以自动完成这种优化。(from 《Effective Java》)
    21         final int prime = 31;
    22         // [STEP2] 为对象中每个有意义的域用下面公式计算散列码 result = prime * result + c
    23         int result = 1;
    24         // boolean
    25         result = prime * result + (a ? 1231 : 1237);
    26         // byte/short/int/char
    27         result = prime * result + b;
    28         result = prime * result + c;
    29         result = prime * result + d;
    30         result = prime * result + e;
    31         // long
    32         result = prime * result + (int) (f ^ (f >>> 32));
    33         // float
    34         result = prime * result + Float.floatToIntBits(g);
    35         // double
    36         long temp;
    37         temp = Double.doubleToLongBits(h);
    38         result = prime * result + (int) (temp ^ (temp >>> 32));
    39         // 对象
    40         result = prime * result + ((i == null) ? 0 : i.hashCode());
    41         // List(要求每个元素实现hashCode)
    42         result = prime * result + ((j == null) ? 0 : j.hashCode());
    43         // 数组(要求每个元素实现hashCode)
    44         result = prime * result + Arrays.hashCode(k);
    45         // [STEP3] 返回
    46         return result;
    47     }
    48     @Override
    49     public boolean equals(Object obj) {
    50         if (this == obj)
    51             return true;
    52         if (obj == null)
    53             return false;
    54         if (getClass() != obj.getClass())
    55             return false;
    56         Test9 other = (Test9) obj;
    57         if (a != other.a)
    58             return false;
    59         if (b != other.b)
    60             return false;
    61         if (c != other.c)
    62             return false;
    63         if (d != other.d)
    64             return false;
    65         if (e != other.e)
    66             return false;
    67         if (f != other.f)
    68             return false;
    69         if (Float.floatToIntBits(g) != Float.floatToIntBits(other.g))
    70             return false;
    71         if (Double.doubleToLongBits(h) != Double.doubleToLongBits(other.h))
    72             return false;
    73         if (i == null) {
    74             if (other.i != null)
    75                 return false;
    76         } else if (!i.equals(other.i))
    77             return false;
    78         if (j == null) {
    79             if (other.j != null)
    80                 return false;
    81         } else if (!j.equals(other.j))
    82             return false;
    83         if (!Arrays.equals(k, other.k))
    84             return false;
    85         return true;
    86     }
    87 }
  • 相关阅读:
    Sql Server 日期时间格式转换
    Windows7中pagefil.sys和Hiberfil.sys文件删除与转移
    64位机的pl/sql不安装32位oracle的连接方式
    cmd下进入oracle sqlplus
    杂七杂八
    做题记录Ⅱ
    SPOJ GSS8
    AGC036 A-Triangle | 构造
    Atcoder 题目泛做
    CF398A Cards | 贪心
  • 原文地址:https://www.cnblogs.com/storml/p/8550463.html
Copyright © 2011-2022 走看看