黑马程序员-----hashCode的作用

------- android培训java培训、期待与您交流! ----------

前言:想要知道hashCode的作用,就必须要知道java中的集合。

java中的集合(Collection)分为两类,一类是list、一类是Set

List集合内的元素是有序的,可以重复。Set集合内的元素是无序的,且不能够重复。

通常想查找一个集合是否包含某个对象,就是逐一取出每个元素与要查找的元素进行比较,当发现某个元素与要查找的元素进行equlas比较相等时,则就停止查找,并返回相应的信息。但如果集合中数据量太大时,这样就会一直equals比较下去,这样太费资源,并且效率也不高。

于是就有人发明了一种哈希算法,提高从集合中查找元素的效率,这种方式将集合分成若干个存储区域,在计算出对象的哈希值,分别分组到对应的区域。根据一个对象的哈希吗就可以查找出对象存储在那个区域。

hashCode方法可以这样理解:它返回的就是根据对象的内存地址换算出的一个值。这样一来,当集合要添加新的元素时,先调用这个元素的hashCode方法,就一下子能定位到它应该放置的物理位置上。如果这个位置上没有元素,它就可以直接存储在这个位置上,不用再进行任何比较了;如果这个位置上已经有元素了,就调用它的equals方法与新元素进行比较,相同的话就不存了,不相同就散列其它的地址。这样一来实际调用equals方法的次数就大大降低了,几乎只需要一两次。

 

再看如下一些示例:


package com.it;
import java.util.Collection;
import java.util.HashSet;
public class Point {
private int x;
private int y;
public Point(int x, int y) {
    super();
    this.x = x;
    this.y = y;
}
@Override
public int hashCode() {
    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;
    final Point other = (Point) obj;
    if (x != other.x)
      return false;
    if (y != other.y)
      return false;
    return true;
}
public static void main(String[] args) {
    Point p1 = new Point(3, 3);
    Point p2 = new Point(5, 5);
    Point p3 = new Point(3, 3);
    Collection<Point> collection = new HashSet<Point>();
    collection.add(p1);
    collection.add(p2);
    collection.add(p3);
    collection.add(p1);
    System.out.println(collection.size());//输出2,此时p1和p3是相等的
}
}

例二(在上例的基础上稍作修改把ArrayList改为HashSet):

package com.it;
import java.util.Collection;
import java.util.HashSet;
public class Point {
private int x;
private int y;
public Point(int x, int y) {
    super();
    this.x = x;
    this.y = y;
}
@Override
public int hashCode() {
    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;
    final Point other = (Point) obj;
    if (x != other.x)
      return false;
    if (y != other.y)
      return false;
    return true;
}
public static void main(String[] args) {
    Point p1 = new Point(3, 3);
    Point p2 = new Point(5, 5);
    Point p3 = new Point(3, 3);
    Collection<Point> collection = new HashSet<Point>();
    collection.add(p1);
    collection.add(p2);
    collection.add(p3);
    collection.add(p1);
    System.out.println(collection.size());//输出2,此时p1和p3是相等的
}
}

例三(如果我们需要p1和p3相等呢?就必须重新hashcode()和equal()方法):

package com.it;
import java.util.Collection;
import java.util.HashSet;
public class Point {
private int x;
private int y;
public Point(int x, int y) {
    super();
    this.x = x;
    this.y = y;
}
@Override
public int hashCode() {
    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;
    final Point other = (Point) obj;
    if (x != other.x)
      return false;
    if (y != other.y)
      return false;
    return true;
}
public static void main(String[] args) {
    Point p1 = new Point(3, 3);
    Point p2 = new Point(5, 5);
    Point p3 = new Point(3, 3);
    Collection<Point> collection = new HashSet<Point>();
    collection.add(p1);
    collection.add(p2);
    collection.add(p3);
    collection.add(p1);
    System.out.println(collection.size());//输出2,此时p1和p3是相等的
}
}


例四(如果我们把hashcode()方法去掉看下):

package com.it;
import java.util.Collection;
import java.util.HashSet;
public class Point {
private int x;
private int y;
public Point(int x, int y) {
    super();
    this.x = x;
    this.y = y;
}
@Override
public boolean equals(Object obj) {
    if (this == obj)
      return true;
    if (obj == null)
      return false;
    if (getClass() != obj.getClass())
      return false;
    final Point other = (Point) obj;
    if (x != other.x)
      return false;
    if (y != other.y)
      return false;
    return true;
}
public static void main(String[] args) {
    Point p1 = new Point(3, 3);
    Point p2 = new Point(5, 5);
    Point p3 = new Point(3, 3);
    Collection<Point> collection = new HashSet<Point>();
    collection.add(p1);
    collection.add(p2);
    collection.add(p3);
    collection.add(p1);
    System.out.println(collection.size());//输出3,此时p1和p3又不相等了
    //原因:虽然此时p1和p2的equals相等,但是他们的hashcode不相等,所以它们就存储在不同区域,在这两个不同的区域存储着相同的东西,查找的时候只在一个区域查找,就被放进去了。
}
}

注:为了避免第四种情况的发生,通常情况下,一个实例的两个对象equals相同,那么他们的hashcode也必须相等,反之,则不成立,当然,只有对象存储在hash算法系列的集合中,hashcode方法才有价值.这样目的就是确保相同的对象存储在相同的位置。

 

总结:(1)通常来说,一个类的两个实例对象用equal方法比较的结果相等时,它们的哈希码也必须相等,但反之则不成立,即equals方法比较结果不相等的对象可以有相同的哈希码,或者说哈希码相同的两个对象的equal方法比较的结果可以不等。

(2)当一个对象被存储进hashset集合中以后,就不能修改这个对象中的那些参与计算哈希值的字段了,否则,对象修改后的哈希值与最初存储进hashset集合时的哈希值就不同了,这种情况下,即使在contains方法使用该对象的当前引用作为的参数去hashset集合中检索对象,也将返回找不到对象的结果,这也会导致无法从hashset集合中单独删除当前对象,从而造成内存泄露,所谓的内存泄露也就说有一个对象不再被使用,但它一直占有内存空间,没有被释放


------- android培训java培训、期待与您交流! ----------

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值