遛马少年,一个代码写的很6的程序员,专注于技术干货分享

最近,在处理线上bug的时候,发现了一个奇怪的现象

业务代码大概是这样的

public static boolean doSth(Integer x, Integer y) {
if (x == y) {
return true;
}
//do other...
return false;
}

当x、y都是较小的值时,比如100、100,正常返回true

当是较大值时,比如500、500,反而返回false

难道100==100,500!=500吗?

带着这样的疑问,我写了个demo程序一探究竟

public class IntDemo {

   public static boolean doSth(Integer a, Integer b) {
if (a == b) {
return true;
}
return false;
} public static void main(String[] args) {
int a = 100;
int b = 500;
System.out.println(doSth(a, a));
System.out.println(doSth(b, b));
}
}

输出结果为:

奇怪!底层是怎么处理的呢?我用javap看了一下上面代码的字节码指令

public class com.integer.IntDemo {
public com.integer.IntDemo();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return public static boolean doSth(java.lang.Integer, java.lang.Integer);
Code:
0: aload_0
1: aload_1
2: if_acmpne 7
5: iconst_1
6: ireturn
7: iconst_0
8: ireturn public static void main(java.lang.String[]);
Code:
0: bipush 100
2: istore_1
3: sipush 500
6: istore_2
7: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
10: iload_1
11: invokestatic #3 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
14: iload_1
15: invokestatic #3 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
18: invokestatic #4 // Method doSth:(Ljava/lang/Integer;Ljava/lang/Integer;)Z
21: invokevirtual #5 // Method java/io/PrintStream.println:(Z)V
24: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
27: iload_2
28: invokestatic #3 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
31: iload_2
32: invokestatic #3 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
35: invokestatic #4 // Method doSth:(Ljava/lang/Integer;Ljava/lang/Integer;)Z
38: invokevirtual #5 // Method java/io/PrintStream.println:(Z)V
41: return
}

可以看到,doSth函数传入的实参是int类型,函数定义的形参却是Integer类型

看到第11行字节码指令我就懂了,原来是通过Integer.valueOf 来做的一个int的自动装箱

11: invokestatic #3 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;

所以,问题肯定出在Integer.valueOf里面,接着,我点开valueOf的源码

public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}

好家伙,这里用到了一个缓存类:IntegerCache

判断如果在缓存范围内,直接返回这个缓存类持有的引用,否则就new一个Integer对象

再点开这个缓存类,low=-128,high=127

这就解释了为什么100是true,500是false了

JDK为什么要设计这样一个很容易掉进去的坑呢?

其实,在valueOf方法上,官方已经给出了说明:

/**
* Returns an {@code Integer} instance representing the specified
* {@code int} value. If a new {@code Integer} instance is not
* required, this method should generally be used in preference to
* the constructor {@link #Integer(int)}, as this method is likely
* to yield significantly better space and time performance by
* caching frequently requested values.
*
* This method will always cache values in the range -128 to 127,
* inclusive, and may cache other values outside of this range.
*
* @param i an {@code int} value.
* @return an {@code Integer} instance representing {@code i}.
* @since 1.5
*/

大概意思就是,-128~127 的数据在 int 范围内是使用最频繁的,为了减少频繁创建对象带来的内存消耗,这里其实是用到了享元模式,以提高空间和时间性能。

既然Integer这样设计了,其他类会不会也有呢?

接着,我又看了其他数据类型,用缓存的还不少,这里我给各位列一下,防止你们以后踩坑

基本类型 包装类型 缓存范围
boolean Boolean -
byte Byte -128-127
short Short -128-127
int Integer -128-127
long Long -128-127
float Float -
double Double -

小伙伴们在开发过程中,也要注意,避免掉进这个坑里。

好了,今天的分享就到这里了,如果你觉得有用,麻烦给兄弟点个小赞,这样我才更有动力去分享更多技术干货~

Java-Integer好大一坑,一不小心就掉进去了的更多相关文章

  1. 关于 Integer 的一个坑

    其实 JDK 中有很多小坑, 我们稍微不注意, 就掉进去了, 然后调了半天 bug, 也不知道为何. 很闹心! 这里说一下, 在Integer中的一个小坑. 看一个小例子: @Test public ...

  2. Java Integer == 以及分析

    Java Integer == 先看一下这段代码 Integer integer1 = 100; Integer integer2 = 100; System.out.println("in ...

  3. IDEA+maven+javafx(java 1.8)入坑记录

    序 好久没写博客了,主要是因为懒,写博客真的是个难坚持的事.但今天登上来看了看,之前记录ctf写的wp竟然点击量这么多了,突然让我有了继续写下去的动力. 这段时间遇到了好多事,中间也有想过写几篇文章记 ...

  4. java integer对象判断两个数字是否相等

    java integer对象判断两个数字是否相等,不一定对 问题发生的背景:javaweb的项目,起先,因为在java中实体类中的int类型在对象初始化之后会给int类型的数据默认赋值为0,这样在很多 ...

  5. Java web 开发填坑记 2 -如何正确的创建一个Java Web 项目

    转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/72566261 本文出自[赵彦军的博客] Java web 开发填坑记 1-如何正确 ...

  6. Java Integer Cache

    Java Integer Cache Java 代码 public class IntegerDemo { public static void main(String[] args) { Integ ...

  7. java中Integer面试的坑

    class Test{ public static void main(String[] args){ //当值在[-128,127]中,不创建新的Integer Integer f1 = 100,f ...

  8. java中的那些坑

    最近准备换工作,为了少让人家鄙视,就要狠狠地藐视这些面试题目.找了本电子书,发了有好多坑,都是特别简单,但是很少有人做对的题目.面对这样的题目,我却有一种兴奋的感觉,也许是因为一直做着重复的工作没有新 ...

  9. Java Integer类分析

    public static final int   MIN_VALUE = 0x80000000;  -2^31 public static final int   MAX_VALUE = 0x7ff ...

  10. 【转】理解Java Integer的缓存策略

    本文将介绍 Java 中 Integer 缓存的相关知识.这是 Java 5 中引入的一个有助于节省内存.提高性能的特性.首先看一个使用 Integer 的示例代码,展示了 Integer 的缓存行为 ...

随机推荐

  1. 【JAVA】详解在JAVA中int与Integer的区别以及背后的原因。

    区别 首先我们要明确,这两点之间有什么区别? 主要有以下几点: 数据类型不同:int是基础数据类型,而 Integer是包装数据类型: 默认值不同:int的默认值是 0,而 Integer的默认值是 ...

  2. [leetcode] 713. Subarray Product Less Than K

    题目 Given an array of integers nums and an integer k, return the number of contiguous subarrays where ...

  3. hyperworks2021位安装教程

    hyperworks2021位安装教程:1.先使用"百度网盘客户端"下载hw21_EN_x64软件安装包到电脑磁盘英文路径文件夹下,并鼠标右击进行解压缩,然后在文件夹内找到hwDe ...

  4. 18道经典链表题刷题总结——WeetCode1 链表系列

    系列文章目录和关于我 前言: WeetCode = Week leetCode 寓意每周刷点leetCode 题目 链表是我恢复刷题手感最喜欢做的系列,其没用太多的算法思想,单纯考验对指针的理解,和c ...

  5. Spring学习笔记 - 第一章 - IoC(控制反转)、IoC容器、Bean的实例化与生命周期、DI(依赖注入)

    Spring 学习笔记全系列传送门: 目录 1.学习概述 2.Spring相关概念 2.1 Spring概述 2.1.1 Spring能做的工作 2.1.2 重点学习的内容 2.1.3 Spring发 ...

  6. MongoDB - 事务支持

    事务简介 事务是数据库中处理的逻辑单元,每个事务中包括一个或多个数据库操作,既可以是读操作,也可以是写操作. ACID 是一个"真正"事务所需要具备的一组属性集合,指的是原子性(A ...

  7. 轻松玩转sed

    sed处理文本方法 1.文本或管道输入 2.读入一行到模式控件 3.sed命令处理 4.输出到屏幕 所以 sed是一个流处理编辑器 sed一次处理一行内容 sed不改变文件内容(可以通过重定向改变文件 ...

  8. ArcObjects SDK开发 007 自定义App-Command-Tool框架

    1.为什么再设计一套App-Command-Tool框架 为什么我们要自己再设计一套App-Command框架,而不直接使用AO API中的AxControl-ICommand这套已经非常好的框架呢? ...

  9. python-py文件打包成exe可执行文件

    方法一::打包完成后可以直接被他人使用,他人不用安装python环境的 可以使用pyinstaller模块实现将python项目打包成exe执行文件 """ 先安装模块 ...

  10. 【每日一题】【list转int数组】【Lambda的简化-方法引用】2022年1月15日-NC45 实现二叉树先序,中序和后序遍历

    描述 给定一棵二叉树,分别按照二叉树先序,中序和后序打印所有的节点.   数据范围:0 \le n \le 10000≤n≤1000,树上每个节点的val值满足 0 \le val \le 1000≤ ...