学习笔记04—HashCode相关

来源:互联网 发布:齐鲁期货软件 编辑:程序博客网 时间:2024/06/05 14:35



导读:

本篇中值得注意的地方一个是HashCode的原理。

明确HashCode的用途在于从集合查找元素。HashCode采取按照哈希码分组分块存储的方式。

另一个有意思的地方是“BB”和“Aa”的哈希码竟然是相同的。。。


还要注意java中内存泄漏多是发生在用到容器的地方。


HashCode

ArrayList和HashSet的比较

1.      ArrayList和HashSet

基础回顾:

public classPoint {   publicintx;   publicinty;   publicPoint(intx, inty) {       this.x = x;       this.y = y;   }}

import java.util.ArrayList;import java.util.Collection; public classReflectTest2 {   publicstaticvoidmain(String[] args) {          Collection c = new ArrayList();          Point p1 = new Point(3, 3);       Point p2 = new Point(5, 5);       Point p3 = new Point(3, 3);        c.add(p1);       c.add(p2);       c.add(p3);       c.add(p1);        System.out.println(c.size()); //结果是4.ArrayList允许重复元素   }}

 

当改为Collection c = new HashSet();时输出3.

 

接下来,我们希望认为内容相同的p1和p3是相等的,需要在Point类中重写hashcode和equals方法


修改后的Point类:


public classPoint {    publicintx;   publicinty;     public Point(int x, int y) {       this.x = x;       this.y = y;   }    @Override   publicinthashCode() {       final int prime = 31;       int result = 1;       result = prime * result + x;       result = prime * result + y;            return result;       }        @Override       public boolean equals(Object obj) {            if (this == obj)                return true;            if (obj == null)                return false;            if (getClass() != obj.getClass())                return false;            Point other = (Point) obj;           if (x != other.x)                return false;            if (y != other.y)                return false;            return true;       }}


 

这时候再运行测试类输出2

Hashcode

2.  Hashcode的作用

 

Hash算法用来提高从集合中查找元素的效率。这种方式将集合分成若干个存储区域,每个对象可以计算出一个哈希码,可以将哈希码分组,每组分别对应某个存储区域。根据一个对象的哈希码就可以确定该对象的存储区域。

 

HashSet就是利用哈希算法存储对象的集合。它内部采用对某个数字取余的方式对哈希码进行分组并划分存储区域。Object类中定义了一个hashCode()方法来返回一个对象的哈希码。当从HashSet集合中查找某个对象时,Java系统首先调用对象的hashCode()方法取得该对象的哈希码,然后根据哈希码找到对应的存储区域,最后取出该区域的每一个元素通过equals方法与对象比较。

 

在38中,如果不重写hashCode方法,那么java会根据对象的内存地址来计算对象的哈希值,这样一来,p1和p3的哈希值是不同的,p3被添加的时候很有可能不会到p1所在的区域去寻找和它内容相同的元素,则p3也会被加入进去。

 

而我们重写hashCode方法,就是要对象的内容参与哈希码运算,保证equals相等的两个对象其哈希码也是相同的。p1和p3内容相同,因而哈希码相同,因而p3被添加的时候会到p1所在的区域去逐个比较,自然会发现p1和它内容相同,于是不会被添加。

 

所以说有个说法叫做:如果两个对象equals相等,那么应该让他们的哈希码相等。如果对象不存到HashSet集合里面就没必要重写hashCode方法了。

 

重复强调一遍。为了保证一个类的实例对象能在HashSet正常存储,要求这个类的两个实例对象用equals比较的结果相等时,他们的哈希码也必须相等。就是说如果obj1.equals(obj2)的结果是true,那么obj1.hashCode() == obj2.hashCode()的结果也要为true.只有类的实例对象采用哈希算法进行存储和检索时,这个类才需要按照要求重写hashCode方法。即使程序可能暂时不会用到当前类的hashCode方法,但是为它提供一个hashCode方法也不会有什么坏处。说不定神马时候又会用到这个方法了。所以,通常要求hashCode方法和equals方法一并重写。

 

注意:equals方法比较不相等的两个对象也可以有相同的哈希码。如

 

String a = "BB";String b = "Aa";System.out.println(a.hashCode()); // 2112System.out.println(b.hashCode()); // 2112


 

这个例子很经典,记住。

内存泄漏

3.  内存泄漏

 

当一个对象被存储进HashSet集合以后就不能修改该对象中参与计算哈希值的字段了。

如在1中添加完四个对象后,再加入下面两行代码

 

p1.y = 7;c.remove(p1);


 

最后输出还是2. 更改p1的y值之后,在remove的时候首先重新计算p1的哈希值,然后去某个区域找p1对象,而p1对象此时呆在另一个区域,所以remove无效。→内存泄漏

如果remove成功了则返回true,反之则返回false.

 


原创粉丝点击