首页 > 编程语言 >Java基础进阶——128陷阱(剖析Integer类的自动拆箱和装箱)

Java基础进阶——128陷阱(剖析Integer类的自动拆箱和装箱)

时间:2024-07-09 22:27:54浏览次数:24  
标签:拆箱 Java 进阶 int 自动 static 128 Integer IntegerCache

一、什么是128陷阱?

下面用一段代码展示了什么是128陷阱:

public static void main(String[] args) {
        Integer a = 10;
        Integer b =  10;

        Integer aa = 127;
        Integer bb =  127;

        Integer aaa=128;
        Integer bbb=128;

        Integer aaaa=130;
        Integer bbbb=130;
        
        System.out.println(a==b);    //true
        System.out.println(aa==bb);  //true
        System.out.println(aaa==bbb);    //false
        System.out.println(aaaa==bbbb);  //false

    }
}

 上述代码运行结果如下:

true
true
false
false

其中在判断(aaa == bbb)和(aaaa==bbbb)时输出了false,很明显输出结果并不符合预期;

而(a==b)和(aa=bb)输出true在逻辑上也并不正确,因为Integer是引用类型,变量用“==”比较的是两个变量的地址;

综上便总结出128陷阱问题是:为什么当两个相同值的Integer对象进行“==”比较时,当值小于128时输出的结果为TRUE;当值大于128时输出为FALSE?

在理解为什么会产生128陷阱之前,我们提前要理解两个知识点:

1.在java中,“==”与equals()方法的区别与特点:

①基本类型一般用“==”来进行比较、效果是直接比较两值是否相等;

②引用类型要用equals()方法进行比较、不同引用类型的equals()方法具有不同的比较方式;

③如果用“==”来比较两个引用类型的变量,实际上比较的是两者的地址是否相等;

注意:在Object类中,equals()方法与“==”功能是相同的;Object下不同的类会按需重写equals()方法。从而不同引用类型的equals()方法具有不同的比较方式。

2.包装类的自动拆箱与封箱:

在Java中我们在创建一个Integer对象时的常用语法为:Integer  a = 10;

而不是像其他类一样通过new关键字类创建对象,这是因为在Java SE5以后,为了减少开发人员的工作,Java提供了自动拆箱与自动装箱功能。

  • 自动装箱:就是将基本数据类型自动转换成对应的包装类。
  • 自动拆箱:就是将包装类自动转换成对应的基本数据类型。
Integer i =10;  //自动装箱
int b= i;     //自动拆箱


Integer i=10 可以替代 Integer i = new Integer(10); 这就是因为Java帮我们提供了自动装箱的功能,不需要开发者手动去new一个Integer对象。

通过观察Integer类的源码我们可以发现;Java是通过类静态方法Integer.valueOf()实现的自动装箱;通过类静态方法intValue()实现的自动拆箱:

//下面两种写法等效(自动装箱)
Integer  a =10;   
Integer a = Integer.valueOf(10);

//下面两种写法等效(自动拆箱)
int b  =  a;         
int b = a.intValue();


二、源码分析

1.Integer.valueOf()的源码

上面我们一直已知,java的自动装箱和拆箱是通过自动调用Integer.valueOf()和Integer.intValue()实现的;我们下面来看看他们的源码;

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

通过valueOf()不难看出,想要理解该方法做了什么,首先要了解IntegerCache是什么

2、IntegerCache是Integer的一个静态内部类,源码如下:
private static class IntegerCache {
        static final int low = -128; //下限是-128
        static final int high;
        static final Integer[] cache;
        static Integer[] archivedCache;

        static {
            // high value may be configured by property(上限high的值可以通过属性进行配置)
            int h = 127;
            String integerCacheHighPropValue =
                VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
            if (integerCacheHighPropValue != null) {
                try {
                    h = Math.max(parseInt(integerCacheHighPropValue), 127);
                    // Maximum array size is Integer.MAX_VALUE
                    h = Math.min(h, Integer.MAX_VALUE - (-low) -1);
                } catch( NumberFormatException nfe) {
                    // If the property cannot be parsed into an int, ignore it.
                }
            }
            high = h;

            // Load IntegerCache.archivedCache from archive, if possible
            // 如果可能,从归档中加载 IntegerCache.archivedCache
            CDS.initializeFromArchive(IntegerCache.class);
            int size = (high - low) + 1;

            // Use the archived cache if it exists and is large enough
            // 如果归档缓存存在且足够大,则使用它
            if (archivedCache == null || size > archivedCache.length) {
                Integer[] c = new Integer[size];
                int j = low;
                for(int i = 0; i < c.length; i++) {
                    c[i] = new Integer(j++);
                }
                archivedCache = c;
            }
            cache = archivedCache;
            // range [-128, 127] must be interned (JLS7 5.1.7)
            assert IntegerCache.high >= 127;
        }

        private IntegerCache() {}
    }

结合上述来个段代码代码;我们可以大致了解;java设计师在设计时,为了减少创建Integer对象的时间开销,提升代码效率,预先创建好了一个静态类IntegerCache;

其中静态成员变量有:

static  final  Integer[]  cache; 静态Integer数组用于存储数值为-128~127的Integer对象共256个

static  final  int  low  =  -128;   用于表示数组最小下标,-128

static  fina  int  high;             用于表示数组最大下标,

因此;我们便知道在Integer对象创建过程中:

Integer a = 10; ——> Integer a = Integer.valueOf(10) ; ——> 而方法valueOf()所做的事有:

1、如果传入的int值在cache缓存-128~127的范围中,则直接返回预先创建好的对象,如果不在范围中,则创建一个新的Integer对象返回。

2、如果传入value数值在-128~127范围内,那么所有在这个范围内创建的数值相同的Integer变量,实际都指向同一个对象,因此地址也相同,所以用“==”比较的结果为true;

3、如果传入value数值不在cache范围内,那么每次被创建的对象都是一个新的对象,即通过new关键字由JVM分配新地址。因此地址不相同,所以用“==”比较的结果为false;

#本篇是参考以下文章后所做的心得体会,当做一篇总结笔记,供大家参考;

Java Integer128陷阱详解_integer 128-CSDN博客

什么是Java中的自动拆装箱_自动装箱-CSDN博客

java 1.8 archive,jar 意思不是Java Archive-CSDN博客

#

标签:拆箱,Java,进阶,int,自动,static,128,Integer,IntegerCache
From: https://blog.csdn.net/Future_yzx/article/details/140286776

相关文章

  • JAVA零基础小白自学日志——第十天
    文章目录1.static修饰变量[1].静态变量的定义[2].静态变量属于类[3]静态变量的初始化[4].静态变量的调用2.static修饰方法[1].静态方法的定义[2].静态方法的调用3.静态块[1].静态块定义[2].静态块和匿名块的演示,运行下程序就能看出来区别小贴士今日提要:记得昨天我......
  • java10
    类特性封装属性私有,get/setprivate在set里面做安全验证继承extends扩展继承关键字子类只用单继承,没有多继承(通俗来讲,你可以有一个亲爸爸,不可能有两个亲爸爸)子类可以继承父类的方法pulic公共的private私有的私有的东西不能继承protected保护的default其他的ctrl+H......
  • Java毕设基于Vue+SpringBoot的汽车租赁管理系统(代码+数据库+文档LW+运行成功)
    文末获取资源,收藏关注不迷路文章目录前言主要使用技术研究内容核心代码文章目录前言快速发展的社会中,人们的生活水平都在提高,生活节奏也在逐渐加快。为了节省时间和提高工作效率,越来越多的人选择利用互联网进行线上打理各种事务,通过线上管理汽车租赁的方式出现......
  • Java毕设基于Vue+SpringBoot的汽车服务管理系统(代码+数据库+文档LW+运行成功)
    文末获取资源,收藏关注不迷路文章目录前言主要使用技术研究内容核心代码文章目录前言随着社会的发展,汽车服务的管理形势越来越严峻。越来越多的用户利用互联网获得信息,但汽车服务信息鱼龙混杂,信息真假难以辨别。为了方便用户更好的获得汽车服务信息,因此,设计一种......
  • Java毕设基于Vue+SpringBoot的校园失物招领平台(代码+数据库+文档LW+运行成功)
    文末获取资源,收藏关注不迷路文章目录前言主要使用技术研究内容核心代码文章目录前言信息化社会内需要与之针对性的信息获取途径,但是途径的扩展基本上为人们所努力的方向,由于站在的角度存在偏差,人们经常能够获得不同类型信息,这也是技术最为难以攻克的课题。针对......
  • JAVA中的反射机制讲解(JAVA基础)
    反射是什么Java反射机制是Java语言一个很重要的特性,它使得Java具有了“动态性”。在Java程序运行时,对于任意的一个类,我们能不能知道这个类有哪些属性和方法呢?对于任意的一个对象,我们又能不能调用它任意的方法?答案是肯定的!这种动态获取类的信息以及动态调用对象方法的功能就来......
  • Java毕设基于Vue+SpringBoot的校园台球厅人员与设备管理系统(代码+数据库+文档LW+运行
    文末获取资源,收藏关注不迷路文章目录前言主要使用技术研究内容核心代码文章目录前言在Internet高速发展的今天,我们生活的各个领域都涉及到计算机的应用,其中包括校园台球厅人员与设备管理系统的网络应用,在外国管理系统已经是很普遍的方式,不过国内的管理网站可能......
  • 如何用Java python php 实现身份实名人证?
    身份证实名认证,也被称为身份证识别或核验身份信息,是指基于直连公安大数据,在用户授权后,通过姓名、身份证号实时快速核验用户身份信息真伪的过程。这种认证方式可以与身份证OCR(光学字符识别)和活体检测技术灵活融合,广泛应用于需要用户实名认证的行业场景,如电商、游戏、直播等。......
  • [NodeJS] JavaScript模块化
    JavaScript诞生于1995年,一开始只是用于编写简单的脚本。随着前端开发任务越来越复杂,JavaScript代码也越来越复杂,全局变量冲突、依赖管理混乱等问题变得十分突出,模块化成为一个必不可少的功能。模块化发展史与方案对比YUI与JQuery2006年,雅虎开源了组件库YUILibrary,使用类似......
  • 【JavaScript脚本宇宙】状态管理利器:JavaScript 库全面解析
    提升项目效率与可维护性:JavaScript状态管理库大揭秘前言在现代前端开发中,状态管理是一个至关重要的话题。随着复杂性的增加,有效地管理应用程序的状态变得越来越具有挑战性。本文将介绍一些流行的JavaScript库,这些库提供了各种方式来管理状态和数据流。欢迎订阅专栏:Ja......