在JDK中String
类是开发人员最常用到的一个类之一,由于String
类对hashCode()
和equals(Object)
方法进行了重写而String
类又是一个被final
修饰的类,所以无法继承该类进行进一步的自定义功能开发,因此了解其内部工作的原理是十分必要的。
hashCode
方法主要用来计算并获取当前对象的hash
值。(提高查找的快捷性,对比两个对象的是否不相同)
在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]; // <- 为什么是31呢?
}
hash = h;
}
return h;
}
hash值的计算通常会使用到一个素数来保证散列的,String
类的作者也在释中给出了 计算原理
s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
// 数学公式就是
f(n) = 31*f(n-1) + value[n];
通过这种常见的方式进行hash值的计算。
为什么要选择31
这个值呢?
没有官方的答案,但是有两种观点:
- 选择值 31 是因为它是一个奇数素数。如果它是偶数并且乘法溢出,则信息将丢失,因为乘以 2 相当于移位。使用素数的优势不太明显,但它是传统的。31 的一个很好的属性是乘法可以用移位和减法代替以获得更好的性能:31 * i == (i << 5) - i. 现代虚拟机自动进行这种优化。
- String.hashCode内部会缓存第一次计算的值,因为这是一个final(不可变)类,也就是String对象的内容是不会变的。这能够在多次put到HashMap的场合提高性能,不过似乎用处不多。
我的观点 是由于String
类所存储的字符主要是Ascii表中的字符,然而使用String
类存储字符串通常不用存过长的字段(String
在进行修改是会重新创建一个对象,这样内存消耗就太大了,通常会使用StringBuffer或者StringBuilder来进行处理)所以为了散列冲突比较小,计算速度又比较快,而31
又是一个字节能存储的梅森素数,多方面取舍之后选择了这个值。
equals(Object)原理作者地址:https://blog.csdn.net/qq_24293403/article/details/124659133
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;
}
对比过程:
- 判断对比对象的内存地址与自己内存地址是否相同,相同直接返回
true
; - 判断对比对象是否是
String
类型的对象,不是直接返回false
; - 判断对比对象的长度与自己的长度是否相同,不相同直接返回
false
; - 通过循环对比两个对象中每一个字符是否相同,如果存在不相同直接返回
false
都相同就返回true
。
作者地址:https://blog.csdn.net/qq_24293403/article/details/124659133
点个赞吧,我很需要。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)