当前位置: 首页 > news >正文

深入解析Java中的“128陷阱“:Integer缓存机制源码分析

目录

一、现象展示

二、源码解析

三、关键点分析

关键点分析

为什么叫"128陷阱"

正确的比较方式(超出缓存范围外的数值)

其他包装类的缓存

四、延伸(关于equals&==哪个更加权威)


“128陷阱”是Java中的一道经典面试题,其中涉及Integer中的缓存机制知识,下面从源码角度解析一下这个问题。

一、现象展示

请仔细查看下面的两段代码:

不难发现看似很正确的等价判断却得到了截然相反的结果。

Integer a = 127;
Integer b = 127;
System.out.println(a == b); // trueInteger c = 128;
Integer d = 128;
System.out.println(c == d); // false

二、源码解析

public static Integer valueOf(int i) {if (i >= IntegerCache.low && i <= IntegerCache.high)return IntegerCache.cache[i + (-IntegerCache.low)];return new Integer(i);
}private static class IntegerCache {static final int low = -128; // 缓存范围的最小值static final int high;       // 缓存范围的最大值static final Integer cache[]; // 缓存数组static {// 静态初始化块,用于初始化缓存范围和缓存数组int h = 127; // 默认缓存范围的最大值String integerCacheHighPropValue =sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");if (integerCacheHighPropValue != null) {try {int i = parseInt(integerCacheHighPropValue); // 尝试解析配置属性i = Math.max(i, 127); // 确保缓存范围至少为 127// 最大缓存范围受限于数组大小限制h = Math.min(i, Integer.MAX_VALUE - (-low) -1);} catch(NumberFormatException nfe) {// 如果解析失败,忽略配置属性}}high = h; // 设置最终的缓存范围最大值cache = new Integer[(high - low) + 1]; // 初始化缓存数组int j = low;for(int k = 0; k < cache.length; k++)cache[k] = new Integer(j++); // 填充缓存数组// 确保缓存范围至少包含 [-128, 127],这是 Java 语言规范的要求assert IntegerCache.high >= 127;}private IntegerCache() {} // 私有构造函数,防止外部实例化
}

三、关键点分析

关键点分析

  1. 缓存范围:默认缓存-128到127之间的Integer对象

    • 下限固定为-128

    • 上限默认为127,但可通过JVM参数-XX:AutoBoxCacheMax=<size>调整

  2. 自动装箱机制:当使用Integer i = 127语法时,实际上调用的是Integer.valueOf(127)

  3. 缓存实现

    • 在Integer类初始化时,会预先创建好缓存范围内的Integer对象

    • 当调用valueOf()时,如果在缓存范围内,直接返回缓存对象

    • 超出范围则新建Integer对象

为什么叫"128陷阱"

  • 对于-128到127之间的值,valueOf()返回的是缓存中的同一个对象,所以==比较为true

  • 对于超出这个范围的值,每次valueOf()都会创建新对象,==比较为false

  • 而使用equals()方法比较时,比较的是实际int值,所以总是正确

正确的比较方式(超出缓存范围外的数值)

Integer a = 128;
Integer b = 128;
System.out.println(a.equals(b)); // true,正确比较内容
System.out.println(a.intValue() == b.intValue()); // true,拆箱比较

其他包装类的缓存

类似的缓存机制也存在于其他包装类中:

  • Byte: 全部缓存(-128~127)

  • Short: -128~127

  • Long: -128~127

  • Character: 0~127

  • Boolean: TRUE和FALSE两个实例

四、延伸(关于equals&==哪个更加权威)

  1. 比较两个对象的内容是否相等,应该使用 equals 方法。
  2. 比较两个引用是否指向同一个对象实例,或者比较基本数据类型的值是否相等,应该使用 == 运算符。
  3. 在实际开发中,equals 更常用于比较对象的内容,因为它可以通过重写来实现更灵活和合理的逻辑。 因此,在比较对象的内容时,equals 是更权威的选择。

【注:】重写equals方法一定要重写其中的hashcode方法。

http://www.dtcms.com/a/269490.html

相关文章:

  • 容器技术入门之Docker环境部署
  • Docker快速部署Hive服务
  • 【技术应用】CUTTag应用实例解析:比ChIP-seq更精准高效的DNA-蛋白互作研究
  • No static resource druid
  • C++(STL源码刨析/vector)
  • 虚幻引擎UE5专用服务器游戏开发-20 添加基础能力类与连招能力
  • Takebishi旗下智能硬件网关产品devicegateway详细介绍
  • ThreadPoolTaskExecutor 的使用案例
  • 【PTA数据结构 | C语言版】求单链表list中的元素个数,即表长
  • NumPy-随机数生成详解
  • AI编程的未来是智能体原生开发?
  • JavaSE-继承
  • UI前端与数字孪生结合实践案例:智慧零售的库存管理优化系统
  • 算法学习笔记:10.Prim 算法——从原理到实战,涵盖 LeetCode 与考研 408 例题
  • 【Mac】实现Docker下载安装【正在逐步完善】
  • 【论文阅读】CogVideoX: Text-to-Video Diffusion Models with An Expert Transformer
  • 【计算机基础理论知识】C++篇(一)
  • 暑假读书笔记第四天
  • 【Python-GEE】如何利用Landsat时间序列影像通过调和回归方法提取农作物特征并进行分类
  • python transformers库笔记(BertForTokenClassification类)
  • 【牛客刷题】小红的与运算
  • node.js中yarn、npm、cnpm详解
  • 精益管理与数字化转型的融合:中小制造企业降本增效的双重引擎
  • 算法训练营DAY29 第八章 贪心算法 part02
  • 实战Linux进程状态观察:R、S、D、T、Z状态详解与实验模拟
  • 联通线路物理服务器选择的关键要点
  • No Hack No CTF 2025Web部分个人WP
  • Django双下划线查询
  • 微信小程序控制空调之接收MQTT消息
  • 如何利用AI大模型对已有创意进行评估,打造杀手级的广告创意