一、类定义与核心特性
Java 的 Integer 类是基本类型 int 的包装类,其源码中第一个值得关注的是类定义:
public final class Integer extends Number implements Comparable<Integer> {
final
修饰:确保Integer
不可被继承,避免子类修改其行为,保证类型安全。- 继承
Number
:Number
是所有数值包装类的抽象父类(如Byte
、Long
),要求子类实现byteValue()
、intValue()
等类型转换方法。 - 实现
Comparable<Integer>
:通过compareTo
方法支持对象间的大小比较,是排序操作的基础。
二、常量与基础属性
1. 边界常量
@Native public static final int MIN_VALUE = 0x80000000; // -2^31
@Native public static final int MAX_VALUE = 0x7fffffff; // 2^31-1
MIN_VALUE
和MAX_VALUE
分别表示int
的最小和最大值,使用十六进制直接定义(0x80000000
对应十进制-2147483648
,0x7fffffff
对应2147483647
)。@Native
注解表示这些常量在本地代码(如 C/C++)中也有定义,用于 JNI 交互。
2. 类型标识
public static final Class<Integer> TYPE = (Class<Integer>) Class.getPrimitiveClass("int");
TYPE
是int
基本类型的Class
对象,通过Class.getPrimitiveClass("int")
获取,用于反射场景(如判断类型是否为基本类型)。
三、缓存机制:IntegerCache
设计背景
自动装箱(Autoboxing)时频繁创建 Integer 对象会影响性能,因此 JDK 引入了缓存机制。
核心实现
private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer cache[];
static {
int h = 127;
// 支持通过 JVM 参数调整缓存上限(-XX:AutoBoxCacheMax)
String integerCacheHighPropValue = sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
try {
int i = parseInt(integerCacheHighPropValue);
h = Math.max(i, 127); // 至少缓存到 127
h = Math.min(i, Integer.MAX_VALUE - (-low) - 1); // 避免数组越界
} catch (NumberFormatException ignored) {}
}
high = h;
// 初始化缓存数组
cache = new Integer[(high - low) + 1];
int j = low;
for (int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
}
}
- 缓存范围:默认缓存
-128
到127
(可通过-XX:AutoBoxCacheMax
调整上限)。 - 初始化时机:类加载时通过静态代码块预先生成缓存数组,避免重复创建对象。
实际应用
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)]; // 直接从缓存获取
return new Integer(i); // 超出范围则新建对象
}
- 当
i
在缓存范围内时,valueOf
直接返回缓存的对象;否则新建对象。 - 注意:自动装箱(如
Integer a = 127;
)底层调用的就是valueOf
,因此Integer a = 127
和Integer b = 127
会指向同一个对象(a == b
为true
),但超出缓存范围时(如128
)则为false
。
四、字符串与整数的转换
1. 整数转字符串:toString(int i)
public static String toString(int i) {
if (i == Integer.MIN_VALUE) // 处理最小值溢出问题
return "-2147483648";
int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i); // 计算字符串长度
char[] buf = new char[size];
getChars(i, size, buf); // 填充字符数组
return new String(buf, true); // 构造字符串(使用包级私有构造函数避免拷贝)
}
- 边界处理:
Integer.MIN_VALUE
取负会溢出,直接返回固定字符串。 - 性能优化:
- 预先计算字符串长度(
stringSize
方法通过查表快速确定长度),避免动态扩容。 getChars
方法通过位运算和查表(DigitTens
、DigitOnes
数组)加速数字到字符的转换,例如:// 大数(>=65536)处理:每次生成两位数字 while (i >= 65536) { q = i / 100; r = i - ((q << 6) + (q << 5) + (q << 2)); // 等价于 i - q*100 buf[--charPos] = DigitOnes[r]; // 个位字符 buf[--charPos] = DigitTens[r]; // 十位字符 i = q; }
- 预先计算字符串长度(
2. 字符串转整数:parseInt(String s, int radix)
public static int parseInt(String s, int radix) throws NumberFormatException {
// 1. 校验参数合法性
if (s == null || radix < Character.MIN_RADIX || radix > Character.MAX_RADIX)
throw new NumberFormatException();
int result = 0;
boolean negative = false;
int i = 0, len = s.length();
int limit = -Integer.MAX_VALUE; // 初始上限(负数处理)
int multmin = limit / radix; // 防止溢出的阈值
// 2. 处理符号位
if (len > 0) {
char firstChar = s.charAt(0);
if (firstChar < '0') {
if (firstChar == '-') {
negative = true;
limit = Integer.MIN_VALUE; // 负数的下限是 MIN_VALUE
} else if (firstChar != '+')
throw new NumberFormatException();
if (len == 1) throw new NumberFormatException(); // 单独符号不合法
i++;
}
// 3. 逐位解析
while (i < len) {
int digit = Character.digit(s.charAt(i++), radix); // 字符转数字
if (digit < 0) throw new NumberFormatException();
if (result < multmin) throw new NumberFormatException(); // 溢出检查
result *= radix;
if (result < limit + digit) throw new NumberFormatException(); // 溢出检查
result -= digit; // 累加(负数处理避免溢出)
}
} else {
throw new NumberFormatException();
}
return negative ? result : -result; // 恢复符号
}
- 核心逻辑:
- 符号处理:支持
+
和-
前缀,默认正数。 - 溢出检测:通过
result < multmin
和result < limit + digit
双重检查,确保结果在int
范围内。 - 负数累加:使用负数累加(
result -= digit
)避免正数累加时溢出(如Integer.MAX_VALUE + 1
会溢出为负数)。
- 符号处理:支持
五、位运算与无符号处理
1. 经典位运算方法
Integer
提供了多个位运算方法(如 highestOneBit
、lowestOneBit
),这些方法基于《Hacker’s Delight》中的算法优化。
highestOneBit(int i)
:获取最高位的1
public static int highestOneBit(int i) {
i |= (i >> 1); // 将最高位右移1位并或操作,填充次高位
i |= (i >> 2); // 右移2位,填充接下来的两位
i |= (i >> 4); // 右移4位,填充接下来的四位
i |= (i >> 8); // 右移8位,填充接下来的八位
i |= (i >> 16); // 右移16位,填充高16位
return i - (i >>> 1); // 最高位保留,其余位清零
}
- 原理:通过多次右移和或操作,将最高位后的所有位填充为1,最后通过
i - (i >>> 1)
得到最高位的1(例如,i=0b1000
处理后变为0b1111
,i - (i>>>1)
得到0b1000
)。
lowestOneBit(int i)
:获取最低位的1
public static int lowestOneBit(int i) {
return i & -i; // 利用补码特性,-i 是 ~i +1,与原数按位与得到最低位的1
}
- 示例:
i=0b10100
,-i=0b01100
(补码),i & -i=0b00100
,即最低位的1。
2. 无符号处理(JDK8+)
JDK8 新增了无符号相关方法(如 toUnsignedString
、compareUnsigned
),用于处理 int
作为无符号数的场景。
toUnsignedString(int i, int radix)
:无符号字符串转换
public static String toUnsignedString(int i, int radix) {
return Long.toUnsignedString(toUnsignedLong(i), radix);
}
private static long toUnsignedLong(int x) {
return ((long) x) & 0xffffffffL; // 将 int 转换为无符号 long(高32位清零)
}
- 逻辑:将
int
转换为无符号long
(通过掩码0xffffffffL
保留低32位),再调用Long
的无符号转换方法。
compareUnsigned(int x, int y)
:无符号比较
public static int compareUnsigned(int x, int y) {
return compare(x + MIN_VALUE, y + MIN_VALUE); // 转换为有符号比较
}
- 原理:无符号数的比较等价于将其视为
x + 2^31
和y + 2^31
的有符号比较(MIN_VALUE = -2^31
,因此x + MIN_VALUE
等价于无符号数的偏移)。
六、设计哲学与最佳实践
1. 不可变性
Integer
的核心字段 value
被 final
修饰:
private final int value;
- 保证
Integer
对象是不可变的,线程安全,适合作为哈希表的键(hashCode
基于value
计算)。
2. 性能优化
- 缓存机制:减少高频小整数的对象创建,提升自动装箱性能。
- 位运算替代算术运算:如
highestOneBit
通过位操作替代循环查找,时间复杂度O(1)
。 - 字符数组预分配:
toString
预先计算字符串长度,避免动态扩容的开销。
3. 最佳实践
- 优先使用
valueOf
:替代构造函数new Integer(int)
,利用缓存提升性能。 - 注意自动装箱陷阱:
Integer a = 128; Integer b = 128;
时a == b
为false
(超出缓存范围),应使用equals
比较值。 - 大数解析用
parseUnsignedInt
:处理无符号大数时避免溢出(如parseUnsignedInt("4294967295", 10)
返回2^32-1
)。
总结
Java的Integer
类是int
的包装类,具有以下核心特性:
- 类定义:
final
修饰确保不可继承,继承Number
实现数值转换,实现Comparable
支持排序。 - 常量:
MIN_VALUE
和MAX_VALUE
定义int范围(-2³¹~2³¹-1
),TYPE
用于反射获取int
类型。 - 缓存优化:通过
IntegerCache
默认缓存-128~127
的Integer
对象,提升自动装箱性能,可通过JVM参数调整上限。 - 字符串转换:
toString()
优化性能,预计算长度并用位运算加速数字转字符;parseInt()
严格处理符号与溢出,支持任意进制转换。
- 位运算:提供高效位操作方法(如
highestOneBit
),基于经典算法实现。
关键点:缓存机制影响对象复用,字符串转换注重边界与溢出处理,位运算方法体现性能优化。