前几天面试,被问了一个hashCode值相等,对象是否相等;对象相等,hashCode是否相等。
突然懵逼了,因为是面试,一下紧张,按照记忆中的说的,完全打错,结果可想而知。 可见自己对这完全不理解,故重新认识一番。
Java对于eqauls方法和hashCode方法是这样规定的:
1、如果两个对象相同,那么它们的hashCode值一定要相同;
2、如果两个对象的hashCode相同,它们并不一定相同(上面说的对象相同指的是用eqauls方法比较。)
对象默认都extends Object ,先看Object对这两个方法的定义:
public boolean equals(Object obj) {
return (this == obj);
}
是不是突然懵逼了,这明明比较对象的内存地址是否相等,也就是判断是不是同一个对象。但是为什么很多情况下都会用equals()去比较内容是否一致呢?
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String) anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
会发现,这种情况下,是String重写了Object类的equals(),有了自己的实现方式,所以平常我们判断字符串内容是否相等用equals()是正确的。而且不止String类重写了,Double、Float也都重写了。
至于hashCode()且看Object类中对它的定义:
public native int hashCode();
可以看到这是一个本地方法,返回的对象的地址值。
而再次拿出String类中的hashCode()方法:
public int hashCode() {
int h = hash;
if (h == 0 && value.length > 0) {
char val[] = value;
for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i];
}
hash = h;
}
return h;
}
最终也是返回一个计算出的hash值,用于判断。
Java中的集合(Collection)有两类,一类是List,再有一类是Set。 前者集合内的元素是有序的,元素可以重复;后者元素无序,但元素不可重复。
当集合要添加新的元素时,先调用这个元素的hashCode方法,就一下子能定位到它应该放置的物理位置上。 如果这个位置上没有元素,它就可以直接存储在这个位置上,不用再进行任何比较了;如果这个位置上已经有元素了, 就调用它的equals方法与新元素进行比较,相同的话就不存了,不相同就散列其它的地址。
public class Test01 {
public static void main(String[] args) {
Name name1 = new Name("24");
Name name2 = new Name("24");
Set set = new HashSet();
set.add(name1);
System.out.println("********************111");
set.add(name2);
System.out.println("********************222");
System.out.println(name1.equals(name2));
System.out.println("********************333");
System.out.println(name1.hashCode());
System.out.println(name2.hashCode());
System.out.println(set);
}
}
class Name {
private String id;
public Name(String id) {
this.id = id;
}
public String toString() {
return this.id;
}
public boolean equals(Object obj) {
if(obj instanceof Name) {
Name name = (Name) obj;
System.out.println("equals:"+name.id);
return (id.equals(name.id));
}
return super.equals(obj);
}
public int hashCode() {
Name name = (Name) this;
System.out.println("Hash:"+name.id);
return id.hashCode();
}
}
运行结果如下:
public class Test01 {
public static void main(String[] args) {
Name name1 = new Name("24");
Name name2 = new Name("24");
List list = new ArrayList();
list.add(name1);
System.out.println("********************111");
list.add(name2);
System.out.println("********************222");
System.out.println(name1.equals(name2));
System.out.println("********************333");
System.out.println(name1.hashCode());
System.out.println(name2.hashCode());
System.out.println(list);
}
}
运行结果如下:
可以看出,set进行添加的时候,先去判断hashCode,而list就不必判断hashCode,它可以保存重复数据,而set判断后,如果有相同值,不进行保存。
总结,这些在学校都是最基础的东西,可惜当初没认真听,后来也是觉得该怎么用就怎么用,也没去思考一些最基本的东西,所以,还是要多理解。