equals在obejct这个原始的类中,是直接比较的两个对象引用 引用的地址值(即对象的地址)。
- object中的equals
public boolean equals(Object obj) {
return (this == obj);
}
其它继承了object的类,一般都会重写equals方法,
例如string ,它的实现具体为:
-
先比较两对象的地址值
-
后比较其字符数组内容。
-
string 的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 sw =new String("232");
String s2 =new String("232");
String s3=s2;
//true
System.out.println(s3==s2);
//false
System.out.println(sw==s2);//对象引用 的等号运算 其实比较的是地址值。
//true
System.out.println(sw.hashCode()==s2.hashCode());//hashcode 可以重写 ,string类型的hashcode 一开始默认为0,之后会重新计算后保存(E(i:0->n) value[i]*31^(n-1) );
//false
System.out.println(sw.equals(s2));//这里字符串重写了equals。(1.8版本 : string类型的equals 是先比较 对象引用引用的地址,之后再比较两者的每个字符);
hashcode 在object中 的实现是使用了本地方法,将对象的地址转化为一个整数(注意 这里 返回的hashcode并不等于 对象的地址 )
而string类型的实现的hashcode 其实是 通过 迭代计算 字符数组的每一个字符 求出的一个和(运算过程中有可能发生整数溢出)。
开始创建一个string对象时,它的hash为0,当第一次调用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; }
那么既然hashcode 是通过计算字符串对象中的字符数组获得的结果,那么相同内容的字符串对象不就直接使用hashcode就可以了吗?何必遍历字符数组一一对比每一个字符呢?
理由大致有两个:
-
上面讲到string类型的hashcode计算时可以会发生数值溢出,那么,这样一来可能两个不同内容的字符串对象就会得到相同的hash值
-
另外 虽然字符数组是用final修饰的,但是里面的字符是可以修改的,所以可能通过篡改其中的字符,但是之前调用了hashcode,并将其返回的hash值保存了起来,导致
hash相等,却实际内容不相等。
//测试当通过反射修改了原来字符串对象中的字符数组的内容。
Class stringClass=(String.class);
Constructor constructor =stringClass.getConstructor(String.class);
String string=(String) constructor.newInstance(sw);
//true
System.out.println(string.hashCode()==sw.hashCode());
Field field = stringClass.getDeclaredField("value");
//设置私有属性可以访问
field.setAccessible(true);
char[] arr= (char[])field.get(string);
//修改其中的内容
arr[0]='+';
field.set(string,arr);
//true
//虽然修改了其中的字符,但是由于之前的hashcode已经算出来了,所以就是用了之前的hashcode值
//这在比较字符串中是不安全的,所以equals没有直接使用hashcode作为相等的依据
System.out.println(string.hashCode() ==sw.hashCode());



