起因:忽然想到平时用的HashMap 当key是字符串的时候为什么总可以覆盖,然后看了String的源码发现:

private final char value[];
private int hash; // Default to 0

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;}

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;}

很显然hashCode和eques方法都是根据char[]数组中的char判断的,但是hashCode函数里面为什么是

h = 31 * h + val[i];这个数字为什么选择31吶,引起了我的兴趣。

下面是知乎上的回答:

The value 31 was chosen because it is an odd prime. If it were even and the multiplication overflowed, information would be lost, as multiplication by 2 is equivalent to shifting. The advantage of using a prime is less clear, but it is traditional. A nice property of 31 is that the multiplication can be replaced by a shift and a subtraction for better performance: 31 * i == (i << 5) - i. Modern VMs do this sort of optimization automatically.

设计者选择 31 这个值是因为它是一个奇质数。如果它是一个偶数,在使用乘法当中产生数值溢出时,原有数字的信息将会丢失,因为乘以二相当于位移。选择质数的优势不是那么清晰,但是这是一个传统。31 的一个优良的性质是:乘法可以被位移和减法替代: 31 * i == (i << 5) - i
现代的 VM 可以自行完成这个优化。
As Goodrich and Tamassia point out, If you take over 50,000 English words (formed as the union of the word lists provided in two variants of Unix), using the constants 31, 33, 37, 39, and 41 will produce less than 7 collisions in each case. Knowing this, it should come as no surprise that many Java implementations choose one of these constants.Coincidentally, I was in the middle of reading the section "polynomial hash codes" when I saw this question.
正如 Goodrich 和 Tamassia 指出的那样,如果你使用 31,33, 37,39 和 41 这几个数值,将其应用于 hashCode 的算法中,每一个数字对超过 50000 个英语单词(由两个 Unix 版本的字典的并集构成)产生的 hash 只会产生少于 7 个的冲突。知道了这个之后,Java 大多数的发行版均会使用这几个数值之一的事实对你也不会显得奇怪了。巧合的是,我是在阅读『多项式哈希值』这一个章节的时候看到这个问题的。

可是为什么java可以s="abcd"这样直接赋值吶?难道和c语言里面的重载一样吗?

但是否定的:

因为 从语言一级来看,java不支持运算符重载,这点是肯定的。

String类的”=”,”+”,”+=”,看似运算符重载,实际不是,只是在java编译器里做了一点手脚。 
java编译器对String的运算符做了特殊处理。

例如:
String s = “a”; 
s += “b”; 
编译器转换成了: 
String s = “a”; 
s = (new StringBuilder()).append(s).append(“b”).toString();

HashSet: 继承的AbstractSet内

public int hashCode() {int h = 0;Iterator<E> i = iterator();while (i.hasNext()) {E obj = i.next();if (obj != null)h += obj.hashCode();}return h;}

Integer:

public int hashCode() {return hashCode(this.value);}public static int hashCode(int var0) {return var0;}

Double:

public int hashCode() {return hashCode(this.value);}public static int hashCode(double var0) {long var2 = doubleToLongBits(var0);return (int)(var2 ^ var2 >>> 32);}

>>:带符号右移。正数右移高位补0,负数右移高位补1

>>>:无符号右移。无论是正数还是负数,高位通通补0。

下面是关于hashCode的一些解释:

Hash是散列的意思,就是把任意长度的输入,通过散列算法变换成固定长度的输出,该输出就是散列值。关于散列值,有以下几个关键结论:

1、如果散列表中存在和散列原始输入K相等的记录,那么K必定在f(K)的存储位置上

2、不同关键字经过散列算法变换后可能得到同一个散列地址,这种现象称为碰撞

3、如果两个Hash值不同(前提是同一Hash算法),那么这两个Hash值对应的原始输入必定不同

HashCode

然后讲下什么是HashCode,总结几个关键点:

1、HashCode的存在主要是为了查找的快捷性,HashCode是用来在散列存储结构中确定对象的存储地址的

2、如果两个对象equals相等,那么这两个对象的HashCode一定也相同

3、如果对象的equals方法被重写,那么对象的HashCode方法也尽量重写

4、如果两个对象的HashCode相同,不代表两个对象就相同,只能说明这两个对象在散列存储结构中,存放于同一个位置

转载于:https://www.cnblogs.com/handsomecui/p/8469336.html

String 源码探究相关推荐

  1. Vue源码探究-全局API

    Vue源码探究-全局API 本篇代码位于vue/src/core/global-api/ Vue暴露了一些全局API来强化功能开发,API的使用示例官网上都有说明,无需多言.这里主要来看一下全局API ...

  2. Mybatis 源码探究 (4) 将sql 语句中的#{id} 替换成 ‘?

    Mybatis 源码探究 (4) 将sql 语句中的#{id} 替换成 '? 出于好奇,然后就有了这篇文章啦. 源码给我的感觉,是一座大山的感觉.曲曲折折的路很多,点进去就有可能出不来. 不过慢慢看下 ...

  3. Mybatis 源码探究 (3)创建 SqlSessionFactory对象 执行sqlSession.getMapper()方法

    Mybatis 源码探究 (3)创建 SqlSessionFactory对象 时隔许久,终于又能接着来搞他啦.Mybatis 一起来探究吧. 先笑会再进入主题吧 开始啦 一.new SqlSessio ...

  4. Mabatis 源码探究(2)Java 获取mybatis-config.xml的输入流 inputStream对象

    关于Mybatis源码探究的专栏. 其我的专业是软件技术这个方向的,mybatis 许久以前就学了,但是心里一直存在一些疑惑.也上网查了,看过各种大佬的博客,对 于Mybatis的理解始终感觉不足.最 ...

  5. Vue源码探究-事件系统

    Vue源码探究-事件系统 本篇代码位于vue/src/core/instance/events.js 紧跟着生命周期之后的就是继续初始化事件相关的属性和方法.整个事件系统的代码相对其他模块来说非常简短 ...

  6. ARouter源码探究

    ARouter源码探究 1. 疑问 如何做到支持直接解析标准URL进行跳转,并自动注入参数到目标页面中? 如何做到支持Multidex.InstantRun? 如何做到映射关系按组分类.多级管理,按需 ...

  7. vue大括号里接受一个函数_vue源码探究(第四弹)

    vue源码探究(第四弹) 结束了上一part的数据代理,这一部分主要讲讲vue的模板解析,感觉这个有点难理解,而且内容有点多,hhh. 模板解析 废话不多说,先从简单的入手. 按照之前的套路,先举一个 ...

  8. spring-boot-2.0.3之quartz集成,数据源问题,源码探究

    前言 开心一刻 着火了,他报警说:119吗,我家发生火灾了. 119问:在哪里? 他说:在我家. 119问:具体点. 他说:在我家的厨房里. 119问:我说你现在的位置. 他说:我趴在桌子底下. 11 ...

  9. 从Spring源码探究AOP代码织入的过程

    随着不断地使用Spring,以及后续的Boot.cloud,不断的体会到这个拯救Java的生态体系的强大,也使我对于这个框架有了极大的好奇心,以至于产生了我为什么不能写一个这样的框架的思考. 通过自学 ...

最新文章

  1. jquery通知插件toastr
  2. 哈夫曼树的生成及哈夫曼编码
  3. bootstrap-fileinput 使用
  4. 数据中心基础设施运维是什么?
  5. Openssl 生成证书server.key and server.crt
  6. SAP loyalty management点击了公式超链接后的处理逻辑
  7. python面向对象之类的成员
  8. python教程自带数据库_python教程自带数据库 | Python学哪个数据库
  9. HDOJ2035 人见人爱A^B
  10. Scrapy_LinkExtractor
  11. JQuery Ajax 在asp.net中使用总结
  12. Linux下Node.js安装及环境配置
  13. CSS动态样式---基础-控制是否添加CSS类
  14. windows xp下 usb驱动编写
  15. Windows系统使用SSH连接远程服务器
  16. Day12:一元N次方程的根(略窥群论一二)
  17. python销毁线程_python线程销毁
  18. Linux系统开机无限重启的解决办法
  19. MACS磁珠标记细胞分选技术
  20. 深度学习降噪方案-RNNoise简介和环境配置

热门文章

  1. 【狂神css笔记】美化网页元素
  2. jpa内网mysql_mysql+jpa简单实现步骤
  3. 软件项目需求调研报告模板下载_需求调研规范
  4. jquery 全国 三联 地址选择
  5. 从客户端中(...)检测到有潜在危险的 Request.Form值
  6. 根据 key值查找数组对象中所有的符合的对象 (递归)
  7. K8S 搭建 nacos 1.4.1 集群(MySQL 8.0)
  8. Axure函数与属性速查
  9. 鼠标悬浮显示文字的简单方法
  10. 【CCCC】L2-015 互评成绩 (25分),,简单模拟,水题,动态数组排序