为什么Java中1==1为真,而128==128为假?基于享元模式的整数缓存原理分析

文摘   2024-10-17 21:17   广东  

今天来谈谈在Java中可能会让你感到惊讶的事情——为什么有时用==比较数字的行为并不像你期望的那样。

你可能会认为,在Java中比较两个数字时只要值相等它总是会返回true,因为两边的数字都是一样的,对吧?事实证明,在Java中并不总是那么简单。

一个小代码片段来说明这一点:

Integer a = 128;
Integer b = 128;
System.out.println(a == b); // false

Integer x = 1;
Integer y = 1;
System.out.println(x == y); // true

现在来解释一下为什么会发生这种情况,这与Java中的整数缓存有关。深入探讨下。

在Java中,对于基本数据类型(如intchar等)的比较,使用的是值比较。而对于对象(如Integer),使用的是引用比较,即比较的是两个引用是否指向同一个对象。然而,对于Integer类型,Java进行了一些特殊的优化,这影响了比较的结果,特别是在自动装箱和拆箱时。

分析

  1. 基本数据类型的比较

  • 对于基本数据类型int1 == 1直接比较的是两个值,因此结果为true
  • Integer对象的比较

    • Java中的Integer类是一个对象包装类,用于包装基本数据类型int的值。

    • 当使用Integer变量进行比较时(如a == b),比较的是两个对象的引用是否相同,而不是它们包装的值。

    • 然而,Java对Integer类进行了优化,对于值在-128到127之间的Integer对象,Java会缓存这些对象,即当你使用自动装箱(如Integer a = 127;)时,如果值在这个范围内,Java会返回缓存中的对象,而不是创建一个新的对象。

    基于享元模式的整数缓存魔力

    Integer类在Java中使用了享元模式(Flyweight Pattern)这一设计模式。享元模式是一种对象结构型模式,它运用共享技术有效地支持大量细粒度对象的复用。在享元模式中,由于存在大量的细粒度对象,如果直接创建这些对象,可能会导致内存占用过高,性能下降。因此,享元模式通过共享对象来减少对象的数量,从而降低内存占用,提高性能。

    具体说,Integer类在Java中实现了对-128到127之间整数的缓存。当创建这些范围内的Integer对象时,Integer类会返回缓存中的对象,而不是创建一个新的对象。这样做可以大大减少对象的创建数量,提高内存利用率和性能。这种缓存机制正是享元模式的一种应用。

    具体情况分析

    • 对于Integer a = 128; Integer b = 128;

      • 因为128不在-128到127的缓存范围内,所以ab分别指向了两个不同的Integer对象,尽管它们的值都是128。
      • 因此,a == b比较的是两个对象的引用,它们不同,所以结果为false
    • 对于Integer x = 1; Integer y = 1;

      • 因为1在-128到127的缓存范围内,所以xy都指向了缓存中的同一个Integer对象。
      • 因此,x == y比较的是两个对象的引用,它们相同(指向同一个对象),所以结果为true

    如何正确比较Integer对象

    • 想要比较两个Integer对象所包装的值,而不是它们的引用,应该使用equals()方法:

      Integer a = 128;
      Integer b = 128;
      System.out.println(a.equals(b)); // true,因为比较的是值
    • 使用equals()方法可以确保无论Integer对象的值是否在缓存范围内,比较的结果都是基于它们的值,而不是引用。

    最后

    • 对于基本数据类型(如int),==操作符比较的是值。
    • 对于对象(如Integer),==操作符比较的是引用。
    • Java对Integer对象进行了缓存优化,对于-128到127之间的值,会返回缓存中的对象。
    • 为了正确比较Integer对象所包装的值,应使用equals()方法。

    太强 ! SpringBoot中出入参增强的5种方法 : 加解密、脱敏、格式转换、时间时区处理

    太强 ! SpringBoot中优化if-else语句的七种绝佳方法实战

    SpringBoot使用EasyExcel并行导出多个excel文件并压缩zip下载
    提升编程效率的利器: Google Guava库中双向映射BitMap
    从MySQL行格式原理看:为什么开发规范中不推荐NULL?数据是如何在磁盘上存储的?
    SpringBoot中使用Jackson实现自定义序列化和反序列化控制的5种方式总结

    提升编程效率的利器: Google Guava库之RateLimiter优雅限流

    深入JVM逃逸分析原理:且看其如何提高程序性能和内存利用率

    必知必会!MySQL索引下推:原理与实战

    深入解析JVM内存分配优化技术:TLAB

    SpringBoot中基于JWT的双token(access_token+refresh_token)授权和续期方案
    SpringBoot中基于JWT的单token授权和续期方案
    SpringBoot中Token登录授权、续期和主动终止的方案(Redis+Token)
    微服务中token鉴权设计的4种方式总结
    提升编程效率的API利器:精通Google Guava库区间范围映射RangeMap
    SpringBoot中Jackson控制序列化和反序列化的注解和扩展点总结【收藏版】

    SpringBoot中大量数据导出方案:使用EasyExcel并行导出多个excel文件并压缩zip后下载

    提升编程效率的API利器:精通Google Guava库之IO工具类
    提升编程效率的API利器:精通Google Guava库二维映射表Table
    提升编程效率的API利器:精通Google Guava库区间范围映射RangeMap
    提升编程效率的利器: Google Guava库中双向映射BitMap
    提升编程效率的利器: Google Guava库之RateLimiter优雅限流
    基于Guava布隆过滤器的海量字符串高效去重实践
    加密算法理论总结:分类与典型算法

    关注『 码到三十五 』,日有所获
                         点赞 和 在看 就是最大的支持

    码到三十五
    主要分享正经的开发技术(原理,架构,实践,源码等),以输出驱动输入;当然偶尔会穿插点生活琐碎,顺便吃个瓜,目的嘛,搞点精准流量,看能不能发发广告。
     最新文章