【面试】高频面试点:从源码角度一篇文章带你搞懂128陷阱!

news2024/9/26 1:28:14

        要理解什么是“128陷阱”,首先来看一段代码:

public static void main(String... strings) {
 
    Integer integer1 = 3;
    Integer integer2 = 3;
 
    if (integer1 == integer2)
        System.out.println("integer1 == integer2");
    else
        System.out.println("integer1 != integer2");
 
    Integer integer3 = 300;
    Integer integer4 = 300;
 
    if (integer3 == integer4)
        System.out.println("integer3 == integer4");
    else
        System.out.println("integer3 != integer4");
 
}

        从代码上看,两个if判断的执行逻辑相同,结果理应相同,而如果你有一定的Java基础,不难得出两个判等操作的结果应该都是false。因为Integer是一个包装类,而“==”进行判断非基础类型变量大小的逻辑是比较其地址是否相同。但是实际运行结果呢?

        造成这种“矛盾”的原因,就是所谓的“128陷阱”。

        要了解“128陷阱”,首先我们要知道什么是“基本数据类型”及其对应的“包装类”。

        我们知道,Java语言中,有8种基本数据类型,但是Java作为一门“面向对象”的语言,使用不属于“对象”的数据类型有时会带来很多麻烦。比如,当我们使用集合类时,我们必须在集合中放入Object类型的元素,也就是我们不能直接把int、double等类型的元素放到集合里。这时候,它们的包装类就产生了。基本数据类型和其对应的包装类型相互转换的过程,就是所谓的“装箱”“拆箱”操作。

基本数据类型

对应的包装类型

byte

java.lang.Byte

short

java.lang.Short

int

java.lang.Integer

long

java.lang.Long

float

java.lang.Float

double

java.lang.Double

boolean

java.lang.Boolean

char

java.lang.Character

        为了减轻开发人员的压力,Java为我们提供了自动拆装箱的功能,例如如下代码的写法是不会报错的。

Integer i =10;  //装箱
int b= i;  //拆箱

        而就是这种自动拆装箱的功能,为我们带来了“128陷阱”。在Java 5中,Integer和int对象通过使用相同的对象引用实现了缓存和重用,从而达到节省内存、提高性能的目的

        我们来看下面这段代码,运行结果已经注释在上面了。

int f = 128;
int f1 = 128;
int g = 127;
Integer g0 = 127;
Integer g1 = 127;
Integer h = 128;
Integer h1 = 128;
        
System.out.println(f == f1); //t
System.out.println(g == g1);    //t
System.out.println(g0 == g1);    //t
System.out.println(h == h1); //f
System.out.println(h.equals(h1)); //t

        大多数情况下,使用“==”进行比较时,如果比较的是基本数据类型,那么会直接比较值是否相同,即第8行代码;如果比较的是引用类型,那么则会比较地址是否相同,如第10行代码。因此对引用类型的比较我们通常会使用equals()来进行,即第12行代码。这些都没有问题。但是可以看到第11行代码同样是引用类型之间的比较,但是却得到了true的结果。这就是128陷阱。

        事实上,在valueOf()方法中,当整数值在-128~127之间时,数值都存储在缓存中,当需要自动装箱时,如果数字在该范围内,就会直接使用缓存中的对象,而不会再重新创建对象,因此相同的值的数据会有同样的地址。在Java 6中,我们可以使用java.lang.Integer.IntegerCache.high来根据实际情况设值该范围的最大值。

        以上就是从原理层面对“128陷阱”产生的原因进行的解释,接下来我们从底层源码上看。

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

        可以看到,当数值介于IntegerCache.low和IntegerCache.high之间时,就会直接从IntegerCache.cache中获取对象,否则才会创建一个新对象。

        而在IntegerCache中,定义了low的值等于-128,而最大值默认为127,开发人员可以通过AutoBoxCacheMax自行修改。 缓存通过for循环实现,存储在一个整数数组中。这个缓存会在Integer类第一次被使用的时候被初始化出来。

  private static class IntegerCache {
        static final int low = -128;
        static final int high;
        static final Integer cache[];

        static {
            // high value may be configured by property
            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);
                    // Maximum array size is Integer.MAX_VALUE
                    h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
                } catch( NumberFormatException nfe) {
                    // If the property cannot be parsed into an int, ignore it.
                }
            }
            high = h;

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

            // range [-128, 127] must be interned (JLS7 5.1.7)
            assert IntegerCache.high >= 127;
        }

        private IntegerCache() {}

        当然,这种缓存行为不仅适用于Integer对象。事实上这种机制存在于所有整数类型的类中,其中ByteShort、 Long的固定范围均为-128 =到127且不可更改。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1909841.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

07-7.3.2 平衡二叉树(AVL)

&#x1f44b; Hi, I’m Beast Cheng &#x1f440; I’m interested in photography, hiking, landscape… &#x1f331; I’m currently learning python, javascript, kotlin… &#x1f4eb; How to reach me --> 458290771qq.com 喜欢《数据结构》部分笔记的小伙伴可以…

【Linux】:服务器用户的登陆、删除、密码修改

用Xshell登录云服务器。 1.登录云服务器 先打开Xshell。弹出的界面点。 在终端上输入命令ssh usernameip_address&#xff0c;其中username为要登录的用户名&#xff0c;ip_address为Linux系统的IP地址或主机名。 然后输入密码进行登录。 具体如下&#xff1a; 找到新建会话…

提高项目效率必备:探索2024年10大最佳需求管理系统

本文将分享2024年10款高效需求管理工具&#xff1a;PingCode、Worktile、Tapd、禅道、Teambition、ClickUp、Tower、Asana、Jira 和 monday.com。 在快速变化的软件开发环境中&#xff0c;选择合适的需求管理工具变得至关重要。项目失败往往源于需求不明确或管理不善&#xff0…

linux权限深度解析——探索原理

前言&#xff1a;本节内容主要讲述的是linux权限相关的内容&#xff0c; linux的权限如果使用root账号是感受不到的&#xff0c; 所以我们要使用普通账号对本节相关内容进行学习&#xff0c;以及一些实验的测试。 然后&#xff0c; 通过linux权限的学习我们可以知道为什么有时候…

记一次 .NET某酒业业务系统 崩溃分析

一&#xff1a;背景 1. 讲故事 前些天有位朋友找到我&#xff0c;说他的程序每次关闭时就会自动崩溃&#xff0c;一直找不到原因让我帮忙看一下怎么回事&#xff0c;这位朋友应该是第二次找我了&#xff0c;分析了下 dump 还是挺经典的&#xff0c;拿出来给大家分享一下吧。 …

成都欣丰洪泰文化传媒有限公司电商服务领航者

在当今数字化浪潮中&#xff0c;电商行业正以前所未有的速度蓬勃发展。作为这片蓝海中的佼佼者&#xff0c;成都欣丰洪泰文化传媒有限公司凭借其专业的电商服务能力和对市场的敏锐洞察力&#xff0c;成为众多品牌信赖的合作伙伴。今天&#xff0c;就让我们一起走进成都欣丰洪泰…

大屏自适应容器组件 v-scale-screen

在vue中&#xff0c;v-scale-screen可用于大屏项目开发&#xff0c;实现屏幕自适应&#xff0c;可根据宽度自适应&#xff0c;高度自适应&#xff0c;和宽高等比例自适应&#xff0c;全屏自适应。 仓库地址&#xff1a;github国内地址&#xff1a;gitee 一、安装 npm instal…

Mysql中存储引擎简介、修改、查询、选择

场景 数据库存储引擎 数据库存储引擎是数据库底层软件组件&#xff0c;数据库管理系统&#xff08;DBMS &#xff09;使用数据引擎进行创建、查询、更新和删除数据的操作。 不同的存储引擎提供不同的存储机制、索引技巧、锁定水平等功能&#xff0c;使用不同的存储引擎还可以…

【C++ 】-vector:新时代动态数组的革新与未来

目录 1. vector的介绍及使用 1.1 vector的介绍 1.1.1 vector是什么 1.1.2 vector的存储机制 1.2 vector的使用 1.2.1 定义和构造函数 1.2.2 迭代器 1.2.3 容量相关操作 1.2.4 元素访问和修改 1.3 迭代器失效问题 2. vector深度剖析及模拟实现 2.1 std::vector的模拟…

【笔记】finalshell中使用nano编辑器GNU

ctrl O 保存 enter 确定 ctrl X 退出 nano编辑 能不用就不用吧 因为我真用不习惯 nano编辑的文件也可以用vim编辑的

网页提示“非私密连接”怎么办?

当网页提示“非私密连接”或“您与该网站的连接不是私密连接”&#xff0c;这通常意味着浏览器无法建立一个安全的HTTPS连接。HTTPS协议是HTTP协议的安全版本&#xff0c;通过SSL协议加密数据传输&#xff0c;以保护用户的数据免受中间人攻击或监听。主要有下面几个原因&#x…

In Search of Lost Online Test-time Adaptation: A Survey--论文笔记

论文笔记 资料 1.代码地址 https://github.com/jo-wang/otta_vit_survey 2.论文地址 https://arxiv.org/abs/2310.20199 3.数据集地址 1论文摘要的翻译 本文介绍了在线测试时间适应(online test-time adaptation,OTTA)的全面调查&#xff0c;OTTA是一种专注于使机器学习…

Apache配置与应用(优化apache)

Apache配置解析&#xff08;配置优化&#xff09; Apache链接保持 KeepAlive&#xff1a;决定是否打开连接保持功能&#xff0c;后面接 OFF 表示关闭&#xff0c;接 ON 表示打开 KeepAliveTimeout&#xff1a;表示一次连接多次请求之间的最大间隔时间&#xff0c;即两次请求之间…

一.5 高速缓存至关重要

这个简单的示例揭示了一个重要的问题&#xff0c;即系统花费了大量的时间把信息从一个地方挪到另一个地方。hello程序的机器指令最初是存放在硬盘上&#xff0c;当程序加载时&#xff0c;它们被复制到主存&#xff1b;当处理器运行程序时&#xff0c;指令又从主存复制到处理器。…

C++报警:warning: zero as null pointer constantstddef.h

源码和警告内容 解决办法&#xff1a; select(0,nullptr,nullptr,nullptr,&delay); 关于NULL和nullptr的区别&#xff1a; 在C中&#xff0c;nullptr和null&#xff08;通常指的是NULL宏&#xff0c;因为C标准中并没有直接定义null关键字&#xff09;都用于表示空指针&am…

基于eBPF的procstat软件追踪等待锁和持有锁的时间

在并发编程中&#xff0c;锁的使用是保证线程安全的重要手段。然而&#xff0c;过度使用锁或者锁竞争可能导致性能瓶颈。为了分析程序中锁的使用情况&#xff0c;我们可以借助procstat软件来追踪程序加锁时间和等待锁的时间。procstat是一个基于eBPF&#xff08;extended Berke…

uniapp安卓端实现语音合成播报

最初尝试使用讯飞语音合成方式,能获取到语音数据,但是数据是base64格式的,在安卓端无法播放,网上有说通过转成blob格式的url可以播放,但是uniapp不支持转换的api;于是后面又想其他办法,使用安卓插件播报原生安卓语音播报插件 - DCloud 插件市场 方案一(讯飞语音合成) 1.在讯飞…

AGE Cypher 查询格式

使用 ag_catalog 中的名为 cypher 的函数构建 Cypher 查询&#xff0c;该函数返回 Postgres 的记录集合。 Cypher() Cypher() 函数执行作为参数传递的 Cypher 查询。 语法&#xff1a;cypher(graph_name, query_string, parameters) 返回&#xff1a; A SETOF records 参…

[240709] X-CMD 发布 v0.3.15:新增 uname、coin、df 和 uptime 模块;优化非 Posix Shell

目录 X-CMD 发布 v0.3.15✨ uname✨ coin✨ df✨ uptime✨ fish | onsh | nu | elv✨ go✨ env X-CMD 发布 v0.3.15 ✨ uname 新增了 uname 模块&#xff0c;用于增强 uname 命令的功能。 ✨ coin 新增了 coin 模块&#xff0c;作为 CoinCap 平台信息查看器。 ✨ df 新增了…

Prometheus+Grafana监控Linux主机

1、安装Prometheus 1.1 、下载Prometheus 下载网址 https://github.com/prometheus/prometheus/releases选择需要的版本 wget https://github.com/prometheus/prometheus/releases/download/v2.53.0/prometheus-2.53.0.linux-amd64.tar.gz1.2、安装Prometheus软件 1.2.1、…