您的位置:首页 > 编程语言 > Java开发

Java基础之hashCode()的作用,以及==、equals()和hashCode()区别

2016-12-27 15:10 609 查看

1 ==、equals()和hashCode()

1.1 ==

  ==操作符用来比较两个基本类型变量时(byte、short、char、int、long、float、double、boolean),比较的是值;用来比较引用类型变量时(非基本类型),比较的是引用的地址。

1.2 equals()

  equals方法是基类Object的方法,用于比较两个对象的内容是否相同,Object类中equals方法的默认实现使用的==操作符比较。

  所有的类都是继承于Object这个基类的,在Object中的基类中定义了一个equals()方法,这个方法的初始行为是比较对象的内存地址,实际开发过程中重写了equals方法,重新定义比较规则,如:String、Integer、Date在这些类重写了equals()方法,而不再是比较类在堆内存中的存放地址了。

1.3 hashCode()

  hashCode()返回的就是对象的存储地址,事实上这种看法是不全面的,确实有些JVM在实现时是直接返回对象的存储地址,但是大多时候并不是这样,只能说可能存储地址有一定关联。hashCode方法的主要作用是为了配合基于散列的集合一起正常运行,这样的散列集合包括HashSet、HashMap以及HashTable(注意:集合中不允许重复的元素存在)。

  当向集合中插入对象时,如何判别在集合中是否已经存在该对象了?

  也许大多数人都会想到调用equals方法来逐个进行比较,这个方法确实可行。但是如果集合中已经存在一万条数据或者更多的数据,如果采用equals方法去逐一比较,效率必然是一个问题。此时hashCode方法的作用就体现出来了,当集合要添加新的对象时,先调用这个对象的hashCode方法,得到对应的hashcode值,实际上在HashMap的具体实现中会用一个table保存已经存进去的对象的hashcode值,如果table中没有该hashcode值,它就可以直接存进去,不用再进行任何比较了;如果存在该hashcode值, 就调用它的equals方法与新元素进行比较,相同的话就不存了,不相同就散列其它的地址,所以这里存在一个冲突解决的问题,这样一来实际调用equals方法的次数就大大降低了.

  说通俗一点:Java中的hashCode方法就是根据一定的规则将与对象相关的信息(比如对象的存储地址,对象的字段等)映射成一个数值,这个数值称作为散列值。下面这段代码是java.util.HashMap的中put方法的具体实现:

// 将“key-value”添加到HashMap中
public V put(K key, V value) {
// 若“key为null”,则将该键值对添加到table[0]中。
if (key == null)
return putForNullKey(value);
// 若“key不为null”,则计算该key的哈希值,然后将其添加到该哈希值对应的链表中。
int hash = hash(key.hashCode());
int i = indexFor(hash, table.length);
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
Object k;
// 若“该key”对应的键值对已经存在,则用新的value取代旧的value。然后退出!
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
//若“该key”对应的键值对不存在,则将“key-value”添加到table中
modCount++;
//将key-value添加到table[i]处
addEntry(hash, key, value, i);
return null;
}


  put方法是用来向HashMap中添加新的元素,从put方法的具体实现可知,会先调用hashCode方法得到该元素的hashCode值,然后查看table中是否存在该hashCode值,如果存在则调用equals方法重新确定是否存在该元素,如果存在,则更新value值,否则将新的元素添加到HashMap中。  

  从这里可以看出,hashCode方法的存在是为了减少equals方法的调用次数,从而提高程序效率。

2 ==和equals()比较

2.1 基本数据类型的值比较使用==

  基本数据类型,也称原始数据类型。它们之间的比较,使用==,比较的是他们的值。 即内容相同,我们就认为是相等的。

public class Test {
public static void main(String[] args) {
int i=5;
int j=5;
if(i==j) {
System.out.println("i和j相等!");
} else {
System.out.println("不相等!");
}
}
}


i和j相等!


2.2 复合数据类型的比较使用equals()

  当(String,Integer,Date) 用==进行比较的时候,比较的是他们在内存中的存放地址,所以除非是同一个new出来的对象,他们的比较后的结果为true,否则比较后结果为false。由以下代码解析:

String str1 = new String("hello");
String str2 = "hello";
String str3 = "h";

System.out.println("str1==str2: " + (str1==str2));  //false
System.out.println("str1.equals(str2): " + str1.equals(str2));  //true

System.out.println("str1.hashCode(): " + str1.hashCode());
System.out.println("str2.hashCode(): " + str2.hashCode());
System.out.println("str3.hashCode(): " + str3.hashCode());


输出结果:



2.3 对象类型比较使用equals()

(1)==号:对比对象实例的内存地址来判断是否是同一对象实例,也可以说是判断对象实例是否物理相等。

(2)equals():当对象实例没有重写Object的equals方法时,equals方法判断的是对象实例的内存地址是否是同一对象实例。

//Object类的源码如下
public boolean equals(Object obj) {
return (this == obj);
}


(3)例子

public class Test {
public static void main(String[] args) {
Student s = new Student("BlueSky");
Student s1 = new Student("BlueSky");
if (s == s1) {
System.out.println("s和是s1相等!");
} else {
System.out.println("s和是s1不相等!");
}
if (s.equals(s1)) {
System.out.println("s和是s1相等!");
} else {
System.out.println("s和是s1不相等!");
}
}
}


s和是s1不相等!
s和是s1不相等!


3 HashCode()与equals()方法的关系

  可以直接根据hashcode值判断两个对象是否相等吗?

  肯定是不可以的,因为不同的对象可能会生成相同的hashcode值。虽然不能根据hashcode值判断两个对象是否相等,但是可以直接根据hashcode值判断两个对象不等,如果两个对象的hashcode值不等,则必定是两个不同的对象。如果要判断两个对象是否真正相等,必须通过equals方法。关系如下:  

如果equals方法得到的结果为true,则两个对象的hashcode值必定相等;

如果equals方法得到的结果为false,则两个对象的hashcode值不一定不同;

如果两个对象的hashcode值不等,则equals方法得到的结果必定为false;

如果两个对象的hashcode值相等,则equals方法得到的结果未知。

4 详细关注链接

数据结构与算法之Collection和Map综述-HashMap

HashMap源码剖析.md
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java hashcode equals