(一) == 运算符
==既可以比较基本类型,也可以比较对象
当使用==比较基本数据类型(int ; float ; char ; short ; byte ; long ; double )时,==运算符只会比较两个基本类型的值;
当使用==比较引用数据类型时,比较的是两个引用的对象是否是同一个,也就是当两个引用指向同一个对象(同一个内存地址)时才返回true;
(二) equals 方法
在java.lang.Object类中equals方法定义如下:
public boolean equals(Object obj) {
return (this == obj);
}
由此可见,在不重写equals方法的情况下,任何对象中的equals方法比较的也是两个引用对象是否指向同一个对象(内存地址);
但是,Object类的equals( )方法很少被使用,因为,多数情况下我们希望比较两个对象的内容,而不是判断两个引用是否指向同一对象,
所以jdk在某些类中通过重写equals方法,来实现比较两个对象的内容。
下面我们以java.lang.String类为例,看看这个类如何重写equals:
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
//instanceof运算符用于判断左边的对象是否是右边的类的实例
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = count;
if (n == anotherString.count) {
char v1[] = value;
char v2[] = anotherString.value;
int i = offset;
int j = anotherString.offset;
while (n-- != 0) {
if (v1[i++] != v2[j++])
return false;
}
return true;
}
}
return false;
}
由上面的代码可看出,当equals两边的变量不是指向同一个内存地址时,equals还会继续比较这两个String的内容,如果该对象与调用该方法的String对象具有相同的字符顺序,则返回true;
(三)hashcode 方法
在java.lang.Object类中equals方法定义如下:
public native int hashCode();
native是本地方法的意思,在Object类中hashCode方法被声明为一个本地方法,说明该方法的实现与本地机器相关,这里我们可以理解为该方法返回的是与实例对象所在的物理地址对应的散列值(通过一定的转换函数将物理地址转换为散列值,例如:通过获取对象的物理地址然后除以8再求余,余数几是计算得到的散列值,我们就认为返回一个不是物理地址的数值,而是一个可以映射到物理地址的值)。
当然我们可以在自己写的类中覆盖hashCode()方法,比如String、Integer、 Double。。。。等等这些类都覆盖了hashcode()方法。
下面是String类中的定义的hashCode方法:
public int hashCode() {
int h = hash;
if (h == 0) {
int off = offset;
char val[] = value;
int len = count;
for (int i = 0; i < len; i++) {
h = 31*h + val[off++];
}
hash = h;
}
return h;
}
总之hashCode的作用便是根据一定的函数算法返回一个与该对象对应的散列值,一个对象对应一个散列值,但是一个散列值可以对应多个对象,由此可见,两个引用对象的hashCode返回值相同并不能说明这两个引用指向同一个对象。
java使用Hash 存储机制存储HashMap ,HashTable,HashSet的值,想了解这些类具体是如何应用Hash存储机制,请看另一篇文章——深入讲解HashMap
概念拓展:
哈希算法将任意长度的二进制值映射为固定长度的较小二进制值,这个小的二进制值称为哈希值;
哈希表是根据设定的哈希函数H(key)和处理冲突方法将一组关键字映象到一个有限的地址区间上,并以关键字在地址区间中的象作为记录在表中的存储位置,这种表称为哈希或散列,所得存储位置称为哈希地址或散列地址。作为线性数据结构与表格和队列等相比,哈希表无疑是查找速度比较快的一种。
(四)关于 String == equals三者之间的笔试题
public class Test{
public static void main(String[] args) {
//java虚拟机有一个字符串池,这样声明的字符串都存放在这个池里
//所以str1和str2指向同一个内存地址
String str1="abc";
String str2="abc";
String str3=new String("abc");
System.out.println(str1=="abc");
System.out.println(str1==str2);
System.out.println(str1==str3);
System.out.println(str1.equals("abc"));
System.out.println(str1.equals(str2));
System.out.println(str1.equals(str3));
}
}
看看运行结果是否和你预想的一样。
运行结果:
true
true
false
true
true
true