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

java中== equals hascode解析

2018-03-11 19:38 369 查看
1.==
java中的==是比较两个对象在JVM中的地址
public class ComAddr{
public static void main(String[] args) throws Exception {
String s1 = "nihao";
String s2 = "nihao";
String s3 = new String("nihao");
System.out.println(s1 == s2); // true
System.out.println(s1 == s3); // false
}
}

运行结果:
ture
false
(1)s1 == s2为true,是因为s1和s2都是字符串字面值"nihao"的引用,指向同一块地址,所以相等。(2)s1 == s3为false,是因为通过new产生的对象在堆中,s3是堆中变量的引用,而是s1是指向字符串字面值"nihao"的引用,地址不同所以不相等。
对象是放在堆中的,栈中存放的是对象的引用(地址)。由此可见'=='是对栈中的值进行比较的。如果要比较堆中对象的内容是否相同,那么就要重写equals方法了。

2.equals
 equals()相等的两个对象,hashcode()一定相等,equals()不相等的两个对象,却并不能证明他们的hashcode()不相等

默认的equals方法,直接调用==,比较对象地址。equlas源码public boolean equals(Object obj) {
return (this == obj);
} 但是string类可以使用equals比较,因为string已经覆盖了object类的equals()方法。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;
}

3.hashcode:
hashCode 默认返回对象在JVM中的存储地址

4.为什么重写equals方法需同时重写hashCode方法
举个例子:
在学校中,是通过学号来判断是不是这个人的。
下面代码中情景为学籍录入,学号 123 被指定给学生 Tom,学号 456 被指定给学生 Jerry,学号 123 被失误指定给 Lily。而在录入学籍的过程中是不应该出现学号一样的情况的。
根据情景需求是不能添加重复的对象,可以通过 HashSet 实现。public class Test {
public static void main(String[] args) {
Student stu = new Student(123,"Tom");
HashSet<Student> set = new HashSet<>();
set.add(stu);
set.add(new Student(456, "Jerry"));
set.add(new Student(123, "Lily"));
Iterator<Student> iterator = set.iterator();
while (iterator.hasNext()) {
Student student = iterator.next();
System.out.println(student.getStuNum() + " --- " + student.getName());
}
}
};
class Student {
private int stuNum;
private String name;
public Student(int stuNum,String name){
this.stuNum = stuNum;
this.name = name;
}
public int getStuNum() {
return stuNum;
}
public String getName() {
return name;
}
@Override
public boolean equals(Object obj) {
if(this==obj)
return true;
if(obj instanceof Student){
if(this.getStuNum()==((Student)obj).getStuNum())
return true;
}
return false;
}
}输出为:
123 --- Lily
456 --- Jerry
123 --- Tom
我们看一下 HashSet 的 add 方法:
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}

其实 HashSet 是通过 HashMap 实现的,由此我们追踪到 HashMap 的 put 方法:
public V put(K key, V value) {
if (table == EMPTY_TABLE) {
inflateTable(threshold);
}
if (key == null)
return putForNullKey(value);
int hash = hash(key);
int i = indexFor(hash, table.length);
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
addEntry(hash, key, value, i);
return null;
}

1.根据 key,也就是 HashSet 所要添加的对象,得到 hashcode,由 hashcode 做特定位运算得到 hash 码;2.利用 hash 码定位找到数组下标,得到链表的链首;3.遍历链表寻找有没有相同的 key,判断依据是 e.hash == hash && ((k = e.key) == key || key.equals(k))。在add Lily 的时候,由于重写了 equals 方法,遍历到 Tom 的时候第二个条件应该是 true;但是因为 hashcode 方法还是使用父类的(默认返回对象的存储地址肯定不相同),故而 Tom 和 Lily的 hashcode 不同也就是 hash 码不同,第一个条件为 false。这里得到两个对象是不同的所以 HashSet 添加 Lily 成功。总结出来原因是没有重写 hashcode 方法,下面改造一下:
public class Test {
public static void main(String[] args) {
Student stu = new Student(123,"Tom");
HashSet<Student> set = new HashSet<>();
set.add(stu);
set.add(new Student(456, "Jerry"));
set.add(new Student(123, "Lily"));
Iterator<Student> iterator = set.iterator();
while (iterator.hasNext()) {
Student student = iterator.next();
System.out.println(student.getStuNum() + " --- " + student.getName());
}
}
};
class Student {
private int stuNum;
private String name;
public Student(int stuNum,String name){
this.stuNum = stuNum;
this.name = name;
}
public int getStuNum() {
return stuNum;
}
public String getName() {
return name;
}
@Override
public boolean equals(Object obj) {
if(this==obj)
return true;
if(obj instanceof Student){
if(this.getStuNum()==((Student)obj).getStuNum())
return true;
}
return false;
}
@Override
public int hashCode() {
return getStuNum();
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: