一 :string类型的==和equals的区别:
结论:"=="是判断两个字符串的内存地址是否相等,equals是比较两个字符串的值是否相等,具体就不做扩展了,有兴趣的同学可以去查看相关的博客。
String s1 = new String("java");
String s2 = new String("java");
System.out.println(s1==s2); //false
System.out.println(s1.equals(s2)); //true
在Java中,equals和hashCode方法是Object中提供的两个方法,string类型重写了equals()方法和hashCod()方法,源码如下:
public boolean equals(Object anObject) {
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;
}
/*返回哈希码,String的哈希码计算方式为s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]*/
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;
}
二:对象equals 和hashcode的关系
结论:当对象的equals()方法被重写时,通常有必要重写 hashCode() 方法,以维护 hashCode 方法的常规协定,该协定声明相等对象必须具有相等的哈希码。如下:
(1)两个对象相等,hashcode一定相等
(2)两个对象不等,hashcode不一定不等
(3)hashcode相等,两个对象不一定相等
(4)hashcode不等,两个对象一定不等
hashcode是用于散列数据的快速存取,如利用HashSet/HashMap/Hashtable类来存储数据时,都是根据存储对象的hashcode值来进行判断是否相同的。这样如果我们对一个对象重写了euqals,意思是只要对象的成员变量值都相等那么euqals就等于true,但 不重写hashcode,那么我们再new一个新的对象,当原对象.equals(新对象)等于true时,两者的hashcode却是不一样的,由此将产生了理解的不一致。
三 :使用HashMap,如果key是自定义的类,就必须重写hashcode()和equals()
A.当put元素时:
1.首先根据put元素的key获取hashcode,然后根据hashcode算出数组的下标位置,如果下标位置没有元素,直接放入元素即可。
2.如果该下标位置有元素(即根据put元素的key算出的hashcode一样即重复了),则需要已有元素和put元素的key对象比较equals方法,如果equals不一样,则说明可以放入进map中。这里由于hashcode一样,所以得出的数组下标位置相同。所以会在该 数组位置创建一个链表,后put进入的元素到放链表头,原来的元素向后移动。
B.当get元素时:
根据元素的key获取hashcode,然后根据hashcode获取数组下标位置,如果只有一个元素则直接取出。如果该位置一个链表,则需要调用equals方法遍历链表中的所有元素与当前的元素比较,得到真正想要的对象。
C. 采用hashcode的好处:
如果我们不使用hashcode,直接使用equals比较,那么我们有10w个元素,put值或者get值时要比较10w次,如果先通过hashcode判断后,我们的效率就会提高很多。
我们可以对比实际生活中,如果有一栋教学楼,一楼是1年级,二楼是2年级,以此类推,六楼是6年级,这时我们需要找5年级2班在哪间教室,通过hashcode直接定位到5楼,然后在5楼一间间找就行了,这样避免从一楼一间一间查看。
四.:代码展示,为什么重写equals时必须重写hashCode方法
我们以一个student 学生类来测试重写equals()和重写hashcode()后,map的get()方法返回值结果,让大家清晰了解为什么重写equals时必须重写hashCode方法
package com.sinaif;
public class Student {
private String name; //姓名
private String sex; //性别
private String idCard;//身份证号
Student(String name,String sex,String idCard){
this.name = name;
this.sex = sex;
this.idCard = idCard;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getIdCard() {
return idCard;
}
public void setIdCard(String idCard) {
this.idCard = idCard;
}
@Override
public boolean equals(Object obj) {
// TODO Auto-generated method stub
if(obj == null){
return false;
}
Student obj1 = (Student)obj;
if(this.name.equals(obj1.getName()) && this.idCard.equals(obj1.getIdCard())){
return true;
}
return false;
}
//@Override
public int hashCode() {
// TODO Auto-generated method stub
String s= this.name + this.idCard;
return s.hashCode();
}
}
public static void main(String[] args) throws Exception {
Map map = new HashMap();
Student s1 = new Student("haly","male","110200");
Student s2 = new Student("haly","female","110200");
map.put(s1, s1);
System.out.println(map.get(s2));
// 当没有重写equals方法和hashcode方法,打印出null
// 当重写equals方法,不重写hashcode方法时,打印出null
// 当重写equals方法,并且重写hashcode方法时,打印出com.test.Student@95fb7d6
}