------- 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集合中单独删除当前对象,从而造成内存泄露,所谓的内存泄露也就说有一个对象不再被使用,但它一直占有内存空间,没有被释放