bug?

前几天有位朋友找我,说:“老哥,老哥,我好像发现了Integer一个bug,你帮我看看什么情况?”,说完给了我两个很简单的demo,上代码。


100 == 100

1000 == 1000

通过代码,我们可以看到,这是很简单的“100100”、“10001000”,但是为什么一个是“true”,一个是“false”,难道真的是bug?

使用Integer的场景

我们平时用Integer,都是用来操作整型数值相关操作,比如Model里面的自增主键id,类型标识type等等。

比如我们有个类型,性别,1 男 2 女;那么我们展示到页面的代码一般会这么写:

public static final Integer MAN = 1;

public static final Integer WOMAN = 1;

... ...

if(MAN == user.getSex()) {

return "男";

} else if(WOMAN == user.getSex()) {

return "女";

}

很常见,基本也没遇到过问题,因为我们也很少类型超过几百上千的,只有特殊场景的设计才有。

Integer是什么,怎么正确比较

我们先看看Integer的定义,打开Integer的源代码文件:

class Ineger

通过截图中的代码,我们可以看到,Integer是class,所以Integer是对象。

我们都知道对象的“==”比较,是比较的两引用对象的指针(内存地址)是否相等,也就是是否指向同一对象。既然是对象,那么Integer的正确比较姿势,肯定是“equals”了,即“a.equals(b)”。

我们再回头看前面的例子,“a”和“b”并不是同一个对象。那为什么“100”可以,“1000”就不可以?

自动装箱拆箱

装箱,是自动将基本数据类型转换为包装器类型;

拆箱,是自动将包装器类型转换为基本数据类型;

在这里我们不对“装箱拆箱”做太多的解释,后续我们再开专题讨论。

回到Integer,简单了解下其装箱拆箱分别做了什么操作。

Integer类型的赋值给int类型,调用intValue()方法进行拆箱赋值;

int类型赋值给Integer,会调用valueOf()方法对int进行装箱赋值。

看下相应的源码:

intValue()

valueOf()
我们可以看到,除了“return new Integer(i)”,还有一段if判断,大致意思我们可以看出来,当在“IntegerCache.low”与“IntegerCache.high”区间的时候,会返回“IntegerCache.cache[]”的一个值。

好了,到此,我们可以看到,当装箱 Integer 的值在一定区间的时候,并不是“new”出来的,而是从 IntegerCache.cache[] 中取出来的。所以我们再看看 IntegerCache 是如何定义的。

Integer 缓冲池 IntegerCache

话不多说,先上源码:

IntegerCache

由于时间有限,我们就看看重点,

for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);

这两行代码,就是初始化了cache[]数组的值,每个值都是对应的数值的Integer对象。

1000 不等于 1000 还是bug吗?

到此,我们已经得知,几个重点:

  1. Integer 是对象
  2. Integer 值比较应该使用 equals()
  3. Integer 有个缓存池 IntegerCache,预初始化 -127 至 127 的 Integer 对象\

再看看demo,使用的是“==”并不是“equals()”,所以这并不是bug,而是比较的方式不对,正确的比较姿势是“equals()”,我们来实践一下看看。

举一反三

同样是装箱拆箱,Long是否也有缓存池呢?Double呢?

My Blog

blog.guijianpan.com

技术交流

听说Integer有bug?1000不等于1000?的更多相关文章

  1. 糟糕,你写的 BUG 要被存1000年了!

    摘要:代码冰封,祖传千年! 把大象放在冰箱需要几步? 三步!把代码放在北极需要几步?纳尼? GitHub刚刚公布了一组照片,你写的代码(BUG)上周已经被打包运往北极保存. 只要你2月2日以前贡献过的 ...

  2. hide(1000)跟show(1000)

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  3. NGUI panel 之下widget最大depth是1000,超过1000时OnClick会出问题!

    经过我的测试发现ngui widget的depth是有限制的!原本以为只要不同panel间的depth设置好了后无论widget depth如何设置都没问题,直到我们项目中出现奇怪的点击问题后才发现这 ...

  4. Java Integer于Int 进行==双等于的内存比较时的一些问题说明

    转自: https://blog.csdn.net/xingkongdeasi/article/details/79618421 部分有所修改: 前言: 越是简单的东西,我们往往越是没有去把它明白,但 ...

  5. java 中 sleep(1000) 和 wait(1000) 的区别?

    1.首先 sleep 方法是Thread类中的静态方法,他的作用是使当前线程暂时睡眠指定的时间,可以不用放在synchronized方法或者代码块中,但是 wait 方法是Object类的方法,它是使 ...

  6. 验证HashSet和HashMap不是线程安全

    JAVA集合类: java.util包下的HashSet和HashMap类不是线程安全的, java.util.concurrent包下的ConcurrentHashMap类是线程安全的. 写2个测试 ...

  7. Java基础教程——包装类

    Java出道之时,自诩为"纯面向对象的语言",意思是之前的所谓"面向对象语言"不纯. 但是,有人指责Java也不纯--8种基本类型并非类类型.为此,Java为他 ...

  8. C++ 类类型转换函数explicit 关键字

    标准数据之间会进行  隐式类型安全转换. 转换规则: 隐式类型转换的问题: #include <iostream> #include <string> using namesp ...

  9. 计算机中K到底是1000还是1024?

    1000和1024的争论,其实是传输领域和存储领域概念不清引起的;在传输领域,1秒钟传输多少字位(即b,bit),肯定是用10进制表示,所以是1kb=1000b,即1秒钟传输1000个比特位;就好像: ...

随机推荐

  1. python中文及符号检测工具带GUI界面

    import tkinter import webbrowser import re #本程序是一个中文字符和中文检测工具 #中文字符自己添加,我只添加了一点 #输入字符串,点击检查文本即可判断有没有 ...

  2. 仿真pda,部署时出现问题

    为什么部署到基于 Windows Mobile 的 Pocket PC 设备或模拟器会因共享冲突错误而失败 自己遇到了网上找到的解决方案http://hi.baidu.com/yeflower/blo ...

  3. k8s集群Job Pod 容器可能因为多种原因失效,想要更加稳定的使用Job负载,有哪些需要注意的地方?

    k8s集群Job Pod 容器可能因为多种原因失效,想要更加稳定的使用Job负载,有哪些需要注意的地方? 面试官:"计数性Job默认完成模式是什么?Indexed模式如何发布自定义索引呢?& ...

  4. 使用Spring框架的好处是什么?

    轻量:Spring 是轻量的,基本的版本大约2MB. 控制反转:Spring通过控制反转实现了松散耦合,对象们给出它们的依赖,而不是创建或查找依赖的对象们. 面向切面的编程(AOP):Spring支持 ...

  5. java线程池源码分析

    我们在关闭线程池的时候会使用shutdown()和shutdownNow(),那么问题来了: 这两个方法又什么区别呢? 他们背后的原理是什么呢? 线程池中线程超过了coresize后会怎么操作呢? 为 ...

  6. 在 Java 中,如何跳出当前的多重嵌套循环?

    在最外层循环前加一个标记如 A,然后用 break A;可以跳出多重循环.(Java 中 支持带标签的 break 和 continue 语句,作用有点类似于 C 和 C++中的 goto 语 句,但 ...

  7. Javascript Promises学习

    Promise对象的三个状态 pending(进行中) fulfilled(已成功) rejected(已失败) Promise代表一个异步操作,对象的状态一旦改变,就不会再改变 Promise构造函 ...

  8. MyBatis 实现一对多有几种方式,怎么操作的?

    有联合查询和嵌套查询.联合查询是几个表联合查询,只查询一次,通过在 resultMap 里面的 collection 节点配置一对多的类就可以完成:嵌套查询是先查 一个表,根据这个表里面的 结果的外键 ...

  9. MySQL主从复制(异步复制与半同步复制)

    1.MySQl主从复制 原理:将主服务器的binlog日志复制到从服务器上执行一遍,达到主从数据的一致状态. 过程:从库开启一个I/O线程,向主库请求Binlog日志.主节点开启一个binlog du ...

  10. 学习ELK日志平台(一)

    一.需求及基础: 场景: 1.开发人员不能登录线上服务器查看详细日志 2.各个系统都有日志,日志数据分散难以查找 3.日志数据量大,查询速度慢,或者数据不够实时 4.一个调用会涉及到多个系统,难以在这 ...