清华主页 - 清华新闻 - 综合时讯 - 正文

走进Java:Integer128陷阱

❀❀❀  大佬求关注~祝你天天开心~  ❀❀❀。

目录。

Integer与int的联系。

1.1 Integer和int的区别。

1.2 Integer与int的相互转换 。

二、装箱。

三、拆箱。


今天在学习Java的时候遇到了以下问题。

public static void main(String[] args) {         Integer num1 = 127;        Integer num2 = 127;        Integer num3 = 128;        Integer num4 = 128;        int num5 = 127;        int num6 = 128;        System.out.println(num1 == num2);        System.out.println(num3 == num4);        System.out.println(num1 == num5);        System.out.println(num6 == num3);    }。

我认为这个问题的输出结果是true、true、true、true。但在运行过程中发现,结果不像想象的那样。正确答案如下。

🌼Integer与int的联系。

Java 5 引入自动装箱(Autoboxing)拆箱(Unboxing)机制,允许 。int。 类型和 。Integer。 自动转换类型。

  • 自动装箱。:将 。int。 类型值自动转换为 。Integer。 对象。
  • 自动拆箱。:将 。Integer。 对象自动转换为 。int。 类型值。

1.1 Integer和int的区别。

1. 类型不同。

  • int。 基本数据类型,整数值直接存储。

  • Integer。 引用类型,存储是对象的引用,在堆内存中指向 。Integer。 对象。

2. 内存使用。

  • int。 整数值࿰直接存储在变量的栈内存中c;占用的内存空间固定为 4 个字节。

  • Integer。 对象存储在堆内存中,除了存储整数值󿀀外c;还需要额外的内存来存储对象的元数据,所以占用的内存空间比较大。

3. 空值处理。

  • int。 基本数据类型,不能为 。null。

  • Integer。 引用类型,可以赋值为 。null。,在某些需要表达的地方 “无值” 场景很有用。

1.2 Integer与int的相互转换 。

在上一篇文章中,类和对象,Integer不是八大基本数据类型中的,Integer类󿼌类似于上一篇文章中提到的学生类。

int转换为intege:包装。

看下面的一行代码。下行代码的执行涉及包装操作。

Integer num1 = 127;

当代码真正执行时,它会变成下面的样子。这是包装操作,它是将基本类型的int变量,Integer变量包装成引用类型。

Integer num1 = Integer.valueOf(127);

Integer转换为int:拆箱。

下面的代码涉及拆箱操作。

Integer num1 = 127;int num2 = num1;

执行代码时会变成这样。这是拆箱操作。

Integer num1 = Ineger.valueOf(127);int num2 = num1.intValue();

🍎二、装箱。

想知道最初的问题,要具体了解󿀌装箱是如何实现的,为何将127装箱比作true࿰?c;False࿰对128装箱后的比较c;现在跟进包装代码。

跟进源代码,我们发现这种方法也判断了我们输入的值,与Integercache的low和high进行比较,如果在low和high之前,然后返回一个值󿀌否则,返回new出来的Integer对象。


IntegerCache.low。

能看到�low实际上是一个值,大小为-128。


IntegerCache.high。

同样的,high也是值,只是似乎没有初始值󿀌这里我们先来看看127。

对于一开始的问题,我们传进的值是127。

Integer num1 = 127; Integer num2 = 127;

 然后这个值就会回来。

return IntegerCache.cache[i + (-IntegerCache.low)];

 IntegerCache.cache实际上是Integer数组,用于存储由Integer类创建的对象。

那么它能有哪些对象呢?看下面的代码。

static {             // high value may be configured by property            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            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;        }。

 这是静态初始块,现在不要说太多󿀌只有当Integer类加载时,它才会执行里面的代码,下面是cache的初始化。

 这是静态初始块,现在不要说太多󿀌只有在Integer类加载时,才会执行内部代码,这里有cache的初始化。我们只需要注意下面的部分。

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;

  1. 我们设置了size(127 + 128) + 1,也就是256。cache初始化的过程如下。cache初始化的过程如下:根据low和high计算size。
  2. Integer数组初始化一个size大小。
  3. 赋值操作对数组#xff0c;也就是说,数组的0~255索引存储在-128~127之间的数字(0)

现在我们已经知道了,cache是一个已初始化的数组,Integer对象的引用存储在-128~127之间。然后回到上访代码。如果我们输入的值在low~high之间,然后将直接从这个cache中获取已创建的Integer变量。

return IntegerCache.cache[i + (-IntegerCache.low)];

现在有一点了解,如果你直接得到已经创建的对象,是不是意味着每次拿的时候都会得到同一个对象?就是这样。

Integer num3 = 128;Integer num4 = 128;

 。假如是128。然后Integer对象࿰将通过new创建c;每次new出来,都是一个全新的对象,因此,如何比较new创建的对象也是false,在引用类型对象之间使用==操作,比较两个对象的地址是否相同,也就是说,与num3和num4相比,num3的内存空间地址是否相同,他们的内容是否都是128,而不是比较。

num1和num2的比较实际上是地址,但是num1和num2指向同一对象,所以是true。


🌹三、拆箱。

拆箱操作非常简单,用intValue()方法返回包装整数。

public static void main(String[] args) {         Integer num1 = 127;        Integer num2 = 127;        Integer num3 = 128;        Integer num4 = 128;        int num5 = 127;        int num6 = 128;        System.out.println(num1 == num2);  // Integer.valueOf(127) == Integer.valueOf(127)        System.out.println(num3 == num4);  // Integer.valueOf(128) == Integer.valueOf(128)        System.out.println(num1 == num5);  // num1.intValue() == 127        System.out.println(num6 == num3);  // num2.intValue() == 128    }。

你现在对这个问题了解得更多了吗?

你现在对这个问题了解得更多了吗?

2025-06-24 11:50:12

相关新闻

最新动态

清华大学新闻中心版权所有,清华大学新闻网编辑部维护,电子信箱: news@tsinghua.edu.cn
Copyright 2001-2020 news.tsinghua.edu.cn. All rights reserved.