【Java源码阅读系列1】深度解析 Java Integer 源码

发布于:2025-06-23 ⋅ 阅读:(14) ⋅ 点赞:(0)

一、类定义与核心特性

Java 的 Integer 类是基本类型 int 的包装类,其源码中第一个值得关注的是类定义:

public final class Integer extends Number implements Comparable<Integer> {
  • final 修饰:确保 Integer 不可被继承,避免子类修改其行为,保证类型安全。
  • 继承 NumberNumber 是所有数值包装类的抽象父类(如 ByteLong),要求子类实现 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_VALUEMAX_VALUE 分别表示int的最小和最大值,使用十六进制直接定义(0x80000000 对应十进制 -21474836480x7fffffff 对应 2147483647)。
  • @Native 注解表示这些常量在本地代码(如 C/C++)中也有定义,用于 JNI 交互。

2. 类型标识

public static final Class<Integer> TYPE = (Class<Integer>) Class.getPrimitiveClass("int");
  • TYPEint 基本类型的 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++);
    }
}
  • 缓存范围:默认缓存 -128127(可通过 -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 = 127Integer b = 127 会指向同一个对象(a == btrue),但超出缓存范围时(如 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 方法通过位运算和查表(DigitTensDigitOnes 数组)加速数字到字符的转换,例如:
      // 大数(>=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 < multminresult < limit + digit 双重检查,确保结果在 int 范围内。
    • 负数累加:使用负数累加(result -= digit)避免正数累加时溢出(如 Integer.MAX_VALUE + 1 会溢出为负数)。

五、位运算与无符号处理

1. 经典位运算方法

Integer 提供了多个位运算方法(如 highestOneBitlowestOneBit),这些方法基于《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 处理后变为 0b1111i - (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 新增了无符号相关方法(如 toUnsignedStringcompareUnsigned),用于处理 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 的核心字段 valuefinal 修饰:

private final int value;
  • 保证 Integer 对象是不可变的,线程安全,适合作为哈希表的键(hashCode 基于 value 计算)。

2. 性能优化

  • 缓存机制:减少高频小整数的对象创建,提升自动装箱性能。
  • 位运算替代算术运算:如 highestOneBit 通过位操作替代循环查找,时间复杂度 O(1)
  • 字符数组预分配toString 预先计算字符串长度,避免动态扩容的开销。

3. 最佳实践

  • 优先使用 valueOf:替代构造函数 new Integer(int),利用缓存提升性能。
  • 注意自动装箱陷阱:Integer a = 128; Integer b = 128; a == bfalse(超出缓存范围),应使用 equals 比较值。
  • 大数解析用 parseUnsignedInt:处理无符号大数时避免溢出(如 parseUnsignedInt("4294967295", 10) 返回 2^32-1)。

总结

Java的Integer类是int的包装类,具有以下核心特性:

  • 类定义final修饰确保不可继承,继承Number实现数值转换,实现Comparable支持排序。
  • 常量MIN_VALUEMAX_VALUE定义int范围(-2³¹~2³¹-1),TYPE用于反射获取int类型。
  • 缓存优化:通过IntegerCache默认缓存-128~127Integer对象,提升自动装箱性能,可通过JVM参数调整上限。
  • 字符串转换
    • toString()优化性能,预计算长度并用位运算加速数字转字符;
    • parseInt()严格处理符号与溢出,支持任意进制转换。
  • 位运算:提供高效位操作方法(如highestOneBit),基于经典算法实现。

关键点:缓存机制影响对象复用,字符串转换注重边界与溢出处理,位运算方法体现性能优化。


网站公告

今日签到

点亮在社区的每一天
去签到