目录
2、Integer a=127 与Integer b=127
前言
在处理内存,性能提升,初始化Interger数据类型的时候,合理利用IntegerCache.cache缓存和BigInteger类型来处理超大整数 时的 精度丢失 和 溢出 问题。int Integer
1、int 和 Integer区别
如下图所示:
1.1、
int 的大小
int 是 Java 的基本数据类型,固定占用 4 字节(32 位)。
- 范围:
- 最小值:-2^31 = -2,147,483,648
- 最大值:2^31 - 1 = 2,147,483,647
1.2、Integer大小
Integer 是 int 的包装类,属于 对象类型,它的大小 不固定,取决于 JVM 实现和运行环境。
总大小:12(对象头) + 4(int) + 0~4(对齐) = 16 字节(典型值)
示例:
Integer a = 100; // 占用约 16 字节(堆内存)
1.3、内存大小
Integer 是对象,包含 对象头(类型指针、MarkWord)、字段(int value)。
⚠️注意:
类型指针---->(指向类元数据),int 是基本类型,直接存储值,没有额外开销。
2、Integer a=127 与Integer b=127
2.1、比较
2.1. 使用 ==
比较
Integer a = 127;
Integer b = 127;
System.out.println(a == b); // true
2.2. 使用 equals()比较
System.out.println(a.equals(b)); // true
2.3. 如果换成 128 呢?
Integer a = 128;
Integer b = 128;
System.out.println(a == b); // false
System.out.println(a.equals(b)); // true
2.2、原因
1. 自动装箱机制
当你写Integer a = 127;,Java 会自动将基本类型 int 转换为 Integer 对象。这个过程会调用 Integer.valueOf(int i) 方法。
2. 缓存机制
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
- 默认缓存范围:-128到 127(可以通过 --XX:AutoBoxCacheMax修改上限)。
- 缓存实现:IntegerCache.cache 是一个静态数组,在类加载时初始化。
2.3、总结
- 127 在缓存范围内:
a
和b
都指向IntegerCache.cache[127],因此 a == b为 true。 - 128 超出缓存范围:
a
和b
会分别创建两个新对象,因此a == b为 false。
3、存放区域
3.1. JVM 内存区域划分
- a 和 b 是引用变量:存放在 虚拟机栈。
- IntegerCache.cache 是静态数组:存放在 方法区(Metaspace)。
- 堆内存:仅存放超出缓存范围的 Integer 对象。
1.虚拟机栈(Stack)
+-------------------+
| a -> 方法区的 cache[127] |
| b -> 方法区的 cache[127] |
+-------------------+
2.方法区(Metaspace)
+-------------------+
| IntegerCache.cache[127] (静态数组元素) |
+-------------------+
3.堆内存(Heap)
+-------------------+
| 仅存放超出缓存范围的 Integer 对象(如 128) |
+-------------------+
3.2、
IntegerCache.cache
1. 静态变量
IntegerCache是 Integer 类的 静态内部类,其 cache 数组是 静态变量。
2. 自动装箱的流程
Integer a = 127; // 自动调用 Integer.valueOf(127)
- Integer.valueOf(int i) 会检查
i
是否在缓存范围内(-128 ~ 127
)。 - 如果在范围内,返回 方法区中的
cache[i + offset]
。 - 如果超出范围,会在 堆内存 中创建新对象。
3.3、关键点总结
示例代码验证:
// 127 在缓存范围内
Integer a = 127;
Integer b = 127;
System.out.println(a == b); // true(a 和 b 指向方法区的同一个对象)
// 128 超出缓存范围
Integer c = 128;
Integer d = 128;
System.out.println(c == d); // false(c 和 d 指向堆中的不同对象)
小结
小结
-128 127
4、扩展知识
4.1、缓存目的
1、性能优化:
小范围整数使用频繁,缓存可以避免重复创建对象,减少 GC 压力。
2、节省内存:
-128到127有 256 个值,缓存后只需 256 个对象,而不是每次新建。
3、一致性:
在缓存范围内,
==
和equals()行为一致,方便代码逻辑判断。
4.2、BigInteger
是 Java 提供的一个 任意精度的整数类,用于处理超出int、long范围的整数运算。它解决了 Java 基本数据类型(如int、long)在处理 超大整数 时的 精度丢失 和 溢出 问题。
1、性能开销:
BigInteger 的运算速度比基本类型慢,适合 必须高精度 的场景(如密码学)。
2、不可变性:
每次运算都会生成新对象,频繁操作可能导致内存浪费。如果需要频繁修改,可以使用 BigDecimal(支持浮点数)。
3、线程安全:
由于不可变性,类似于String,BigInteger 是线程安全的,无需额外同步。
4、初始化方式
BigInteger a = new BigInteger("12345678901234567890");
应用场景: