1.==
- 若操作数的类型是基本数据类型,则该关系操作符判断的是左右两边操作数的值是否相等
- 若操作数的类型是引用数据类型,则该关系操作符判断的是左右两边操作数的内存地址是否相同。也就是说,若此时返回true,则该操作符作用的一定是同一个对象。
int a=1;
int b=1;
System.out.println(a==b);//true
Integer i1=new Integer(1);
Integer i2=new Integer(1);
System.out.println(i1==i2);//false
2.equal()
equals方法是基类Object中的实例方法,因此对所有继承于Object的类都会有该方法。
public boolean equals(Object obj) {
return (this == obj);
}
那么问题来了,equal和==的区别又在哪里呢?先来看一个例子:
String str1 = new String("hello");
String str2 = new String("hello");
System.out.println(str1.equals(str2));//true
按照Object类里的方法,str1和str2是两个不同的对象,为何结果是true?
原来是 String 类重写了 equals 方法:巧妙地转化为了值比较
public boolean equals(Object anObject) { // 方法签名与 Object类 中的一致
if (this == anObject) { // 先判断引用是否相同(是否为同一对象),
return true;
}
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方法,内部实现分为三个步骤:
1 先比较引用是否相同(是否为同一对象)
2 再判断类型是否一致(是否为同一类型)
3 最后比较内容是否一致
Java 中所有内置的类的 equals 方法的实现步骤均是如此,特别是诸如 Integer,Double 等包装器类。
equals 重写原则
对象内容的比较才是设计equals()的真正目的,Java语言对equals()的要求如下,这些要求是重写该方法时必须遵循的:
对称性: 如果x.equals(y)返回是“true”,那么y.equals(x)也应该返回是“true” ;
自反性: x.equals(x)必须返回是“true” ;
类推性: 如果x.equals(y)返回是“true”,而且y.equals(z)返回是“true”,那么z.equals(x)也应该返回是“true” ;
一致性: 如果x.equals(y)返回是“true”,只要x和y内容一直不变,不管你重复x.equals(y)多少次,返回都是“true” ;
任何情况下,x.equals(null)【应使用关系比较符 ==】,永远返回是“false”;x.equals(和x不同类型的对象)永远返回是“false”
- equal方法其本意 是 比较两个对象的 content 是否相同
3.hashcode()
hashCode 方法是基类Object中的 实例native方法,因此对所有继承于Object的类都会有该方法。
public native int hashCode();
在 Java 中,由 Object 类定义的 hashCode 方法会针对不同的对象返回不同的整数(散列码)。
hashCode 的常规协定是:
在 Java 应用程序执行期间,在对同一对象多次调用 hashCode 方法时,必须一致地返回相同的整数,前提是将对象进行 equals 比较时所用的信息没有被修改。从某一应用程序的一次执行到同一应用程序的另一次执行,该整数无需保持一致。
如果根据 equals(Object) 方法,两个对象是相等的,那么对这两个对象中的每个对象调用 hashCode 方法都必须生成相同的整数结果。
如果根据 equals(java.lang.Object) 方法,两个对象不相等,那么对这两个对象中的任一对象上调用 hashCode 方法 不要求 一定生成不同的整数结果。但是,程序员应该意识到,为不相等的对象生成不同整数结果可以提高哈希表的性能。
要想进一步了解 hashCode 的作用,我们必须先要了解Java中的容器,因为 HashCode 只是在需要用到哈希算法的数据结构中才有用,比如 HashSet, HashMap 和 Hashtable。
Java中的集合(Collection)有三类,一类是List,一类是Map,再有一类就是Set。 前两个集合内的元素是有序的,元素可以重复;最后一个集合内的元素无序,但元素不可重复。
那么, 这里就有一个比较严重的问题:要想保证元素不重复,可两个元素是否重复应该依据什么来判断呢? 这就是 Object.equals 方法了。但是,如果每增加一个元素就检查一次,那么当元素很多时,后添加到集合中的元素比较的次数就非常多了。 也就是说,如果集合中现在已经有1000个元素,那么第1001个元素加入集合时,它就要调用1000次equals方法。这显然会大大降低效率。于是,Java采用了哈希表的原理。 这样,我们对每个要存入集合的元素使用哈希算法算出一个值,然后根据该值计算出元素应该在数组的位置。所以,当集合要添加新的元素时,可分为两个步骤:
先调用这个元素的 hashCode 方法,然后根据所得到的值计算出元素应该在数组的位置。如果这个位置上没有元素,那么直接将它存储在这个位置上;
如果这个位置上已经有元素了,那么调用它的equals方法与新元素进行比较:相同的话就不存了,否则,将其存在这个位置对应的链表中(Java 中 HashSet, HashMap 和 Hashtable的实现总将元素放到链表的表头)。
总结:hashcode适用于快速检索
4.为什么重写equals一定要重写hashcode?
equals 与 hashCode
前提: 谈到hashCode就不得不说equals方法,二者均是Object类里的方法。由于Object类是所有类的基类,所以一切类里都可以重写这两个方法。
原则 1 : 如果 x.equals(y) 返回 “true”,那么 x 和 y 的 hashCode() 必须相等 ;
原则 2 : 如果 x.equals(y) 返回 “false”,那么 x 和 y 的 hashCode() 有可能相等,也有可能不等 ;
原则 3 : 如果 x 和 y 的 hashCode() 不相等,那么 x.equals(y) 一定返回 “false” ;
原则 4 : 一般来讲,equals 这个方法是给用户调用的,而 hashcode 方法一般用户不会去调用 ;
原则 5 : 当一个对象类型作为集合对象的元素时,那么这个对象应该拥有自己的equals()和hashCode()设计,而且要遵守前面所说的几个原则。
上图展示了Student类的重写后的equals方法和hashcode方法,建议大家用eclipse自动生成,尽量不要自己敲因为很有可能会出错。
现在有两个Student对象:
Student s1=new Student("小明",18);
Student s2=new Student("小明",18);
此时s1.equals(s2)一定返回true
假如只重写equals而不重写hashcode,那么Student类的hashcode方法就是Object默认的hashcode方法,由于默认的hashcode方法是根据对象的内存地址经哈希算法得来的,显然此时s1!=s2,故两者的hashcode不一定相等。
然而重写了equals,且s1.equals(s2)返回true,根据hashcode的规则,两个对象相等其哈希值一定相等,所以矛盾就产生了,因此重写equals一定要重写hashcode,而且从Student类重写后的hashcode方法中可以看出,重写后返回的新的哈希值与Student的两个属性有关。