10 Integer —— 最常用的整数包装类深度解析

Integer ------ 最常用的整数包装类深度解析

适用版本: JDK 8 难度等级: 核心 核心概念: IntegerCache、自动装箱拆箱、位运算方法集、进制转换


一、Integer 的类结构

java 复制代码
public final class Integer extends Number implements Comparable<Integer> {

    @Native public static final int MIN_VALUE = 0x80000000;   // -2^31
    @Native public static final int MAX_VALUE = 0x7fffffff;   // 2^31 - 1

    public static final Class<Integer> TYPE
        = (Class<Integer>) Class.getPrimitiveClass("int");

    public static final int SIZE = 32;
    public static final int BYTES = SIZE / Byte.SIZE;

    private final int value;

    private static final long serialVersionUID = 1360826667806852920L;
}

二、IntegerCache ------ 面试必问的缓存机制

java 复制代码
private static class IntegerCache {
    static final int low = -128;
    static final int high;
    static final Integer cache[];

    static {
        // 默认缓存 -128 ~ 127
        int h = 127;
        String integerCacheHighPropValue =
            sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
        if (integerCacheHighPropValue != null) {
            try {
                int i = parseInt(integerCacheHighPropValue);
                i = Math.max(i, 127);
                // 防止缓存数组过大
                h = Math.min(i, Integer.MAX_VALUE - (-low) - 1);
            } catch (NumberFormatException nfe) {
                // 配置错误则忽略
            }
        }
        high = h;
        cache = new Integer[(high - low) + 1];
        int j = low;
        for (int k = 0; k < cache.length; k++) {
            cache[k] = new Integer(j++);
        }
    }

    private IntegerCache() {}
}

缓存生效场景

java 复制代码
public class IntegerCacheDemo {
    public static void main(String[] args) {
        // 自动装箱会调用 Integer.valueOf(int),走缓存
        Integer a = 127;
        Integer b = 127;
        System.out.println(a == b);  // true------都是缓存中同一对象

        Integer c = 128;
        Integer d = 128;
        System.out.println(c == d);  // false------超出缓存范围,各自 new

        // 显式调用 valueOf 同样走缓存
        System.out.println(Integer.valueOf(100) == Integer.valueOf(100)); // true

        // new Integer 始终不走缓存
        System.out.println(new Integer(100) == new Integer(100)); // false
    }
}

调整缓存上限

bash 复制代码
# 设置缓存上限为 1000
java -Djava.lang.Integer.IntegerCache.high=1000 MyApp

三、自动装箱与拆箱

java 复制代码
public class BoxingDemo {
    public static void main(String[] args) {
        // 装箱:int → Integer ------ 编译器生成 Integer.valueOf(i)
        Integer boxed = 42;   // 等价于 Integer.valueOf(42)

        // 拆箱:Integer → int ------ 编译器生成 integer.intValue()
        int unboxed = boxed;  // 等价于 boxed.intValue()

        // 运算时自动拆箱
        Integer x = 100, y = 200;
        Integer z = x + y;    // 拆箱 → 计算 → 装箱

        // 三目运算符的隐藏陷阱
        Integer n1 = null;
        // 下面这行会抛出 NullPointerException(n1 拆箱为 int 时)
        // int result = true ? n1 : 0;
    }

    // 实际编译后的字节码等价于:
    // Integer boxed = Integer.valueOf(42);
    // int unboxed = boxed.intValue();
}

四、进制转换方法

4.1 toString(int i, int radix)

java 复制代码
public static String toString(int i, int radix) {
    if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX)
        radix = 10;
    if (radix == 10) return toString(i);
    char buf[] = new char[33];
    boolean negative = (i < 0);
    int charPos = 32;
    if (!negative) i = -i;
    while (i <= -radix) {
        buf[charPos--] = digits[-(i % radix)];
        i = i / radix;
    }
    buf[charPos] = digits[-i];
    if (negative) buf[--charPos] = '-';
    return new String(buf, charPos, (33 - charPos));
}
java 复制代码
public class RadixDemo {
    public static void main(String[] args) {
        int val = 255;
        System.out.println("十进制: " + Integer.toString(val, 10));  // 255
        System.out.println("二进制: " + Integer.toString(val, 2));   // 11111111
        System.out.println("八进制: " + Integer.toString(val, 8));   // 377
        System.out.println("十六进制: " + Integer.toString(val, 16)); // ff
        System.out.println("三十二进制: " + Integer.toString(val, 32)); // 7v
    }
}

4.2 toHexString / toOctalString / toBinaryString

java 复制代码
public static String toHexString(int i) {
    return toUnsignedString0(i, 4);  // 4位一组 → 十六进制
}

public static String toOctalString(int i) {
    return toUnsignedString0(i, 3);  // 3位一组 → 八进制
}

public static String toBinaryString(int i) {
    return toUnsignedString0(i, 1);  // 1位一组 → 二进制
}

五、parseInt ------ 字符串解析精要

java 复制代码
public static int parseInt(String s, int radix) throws NumberFormatException {
    if (s == null) throw new NumberFormatException("null");
    if (radix < Character.MIN_RADIX)
        throw new NumberFormatException("radix " + radix + " less...");
    if (radix > Character.MAX_RADIX)
        throw new NumberFormatException("radix " + radix + " greater...");

    int result = 0;
    boolean negative = false;
    int i = 0, len = s.length();
    int limit = -Integer.MAX_VALUE;

    if (len > 0) {
        char firstChar = s.charAt(0);
        if (firstChar < '0') {
            if (firstChar == '-') { negative = true; limit = Integer.MIN_VALUE; }
            else if (firstChar != '+') throw NumberFormatException.forInputString(s);
            if (len == 1) throw NumberFormatException.forInputString(s);
            i++;
        }
        int multmin = limit / radix;
        while (i < len) {
            int digit = Character.digit(s.charAt(i++), radix);
            if (digit < 0) throw NumberFormatException.forInputString(s);
            if (result < multmin) throw NumberFormatException.forInputString(s);
            result *= radix;
            if (result < limit + digit) throw NumberFormatException.forInputString(s);
            result -= digit;
        }
    } else {
        throw NumberFormatException.forInputString(s);
    }
    return negative ? result : -result;
}

设计亮点 :使用负累加 而非正累加,避免 Integer.MIN_VALUE 取负时的溢出问题。


六、位运算方法

6.1 highestOneBit / lowestOneBit

java 复制代码
public static int highestOneBit(int i) {
    i |= (i >> 1);
    i |= (i >> 2);
    i |= (i >> 4);
    i |= (i >> 8);
    i |= (i >> 16);
    return i - (i >>> 1);
}

public static int lowestOneBit(int i) {
    return i & -i;  // 利用补码特性
}
java 复制代码
public class BitDemo {
    public static void main(String[] args) {
        int val = 18;  // 二进制: 00010010

        System.out.println("highestOneBit(18): " + Integer.highestOneBit(val));  // 16
        System.out.println("lowestOneBit(18):  " + Integer.lowestOneBit(val));    // 2

        // highestOneBit 的应用:快速找到 <= n 的最大2的幂
        System.out.println("2^{log2(100)}: " + Integer.highestOneBit(100)); // 64
    }
}

6.2 bitCount ------ 统计 1 的个数

java 复制代码
public static int bitCount(int i) {
    i = i - ((i >>> 1) & 0x55555555);
    i = (i & 0x33333333) + ((i >>> 2) & 0x33333333);
    i = (i + (i >>> 4)) & 0x0f0f0f0f;
    i = i + (i >>> 8);
    i = i + (i >>> 16);
    return i & 0x3f;
}

6.3 numberOfLeadingZeros / numberOfTrailingZeros

java 复制代码
public static int numberOfLeadingZeros(int i) {
    if (i == 0) return 32;
    int n = 1;
    if (i >>> 16 == 0) { n += 16; i <<= 16; }
    if (i >>> 24 == 0) { n += 8;  i <<= 8;  }
    if (i >>> 28 == 0) { n += 4;  i <<= 4;  }
    if (i >>> 30 == 0) { n += 2;  i <<= 2;  }
    n -= i >>> 31;
    return n;
}

七、decode ------ 多进制解码器

java 复制代码
public static Integer decode(String nm) throws NumberFormatException

解码规则:

前缀 进制 示例
0x / 0X 十六进制 0xFF → 255
# 十六进制 #FF → 255
0 八进制 0377 → 255
无前缀 十进制 255 → 255
java 复制代码
public class DecodeDemo {
    public static void main(String[] args) {
        System.out.println(Integer.decode("255"));    // 255
        System.out.println(Integer.decode("0xFF"));   // 255
        System.out.println(Integer.decode("0XFF"));   // 255
        System.out.println(Integer.decode("#FF"));    // 255
        System.out.println(Integer.decode("-0xFF"));  // -255
        System.out.println(Integer.decode("0377"));   // 255(八进制)
    }
}

八、无符号运算(JDK 8 新增)

java 复制代码
// 无符号除法
public static int divideUnsigned(int dividend, int divisor)

// 无符号取余
public static int remainderUnsigned(int dividend, int divisor)

// 无符号比较
public static int compareUnsigned(int x, int y)

// 无符号字符串转换
public static String toUnsignedString(int i, int radix)
java 复制代码
public class UnsignedOperationsDemo {
    public static void main(String[] args) {
        // -1 的 int 表示用 Unsigned 解读就是 2^32 - 1 = 4294967295
        int signedNegative = -1;

        System.out.println("无符号值: " + Integer.toUnsignedString(signedNegative));
        System.out.println("无符号 ÷ 3: "
            + Integer.divideUnsigned(signedNegative, 3));
        System.out.println("无符号 % 3: "
            + Integer.remainderUnsigned(signedNegative, 3));
    }
}

九、综合实战:IP 地址与 int 互转

java 复制代码
/**
 * IPv4 地址(点分十进制)与 int 值的互换
 * 常用在 Redis/MySQL 中存储 IP 地址
 */
public class IpConverter {

    public static int ipToInt(String ip) {
        String[] parts = ip.split("\\.");
        if (parts.length != 4) {
            throw new IllegalArgumentException("非法IP: " + ip);
        }
        // 将4个字节组装成一个int(大端序)
        return (Integer.parseInt(parts[0]) << 24)
             | (Integer.parseInt(parts[1]) << 16)
             | (Integer.parseInt(parts[2]) << 8)
             | Integer.parseInt(parts[3]);
    }

    public static String intToIp(int ip) {
        return ((ip >> 24) & 0xFF) + "."
             + ((ip >> 16) & 0xFF) + "."
             + ((ip >> 8)  & 0xFF) + "."
             + (ip         & 0xFF);
    }

    public static void main(String[] args) {
        String ip = "192.168.1.100";
        int intVal = ipToInt(ip);
        System.out.println("IP → int: " + intVal);             // -1062731364
        System.out.println("无符号形式: "
            + Integer.toUnsignedString(intVal));                // 3232235876
        System.out.println("int → IP: " + intToIp(intVal));    // 192.168.1.100
    }
}

十、综合实战:简易 BitMap 实现

java 复制代码
/**
 * 基于 int[] 和 Integer 位运算的轻量级 BitMap
 * 适用于用户签到、去重计数等场景
 */
public class SimpleBitMap {
    private final int[] bits;
    private final int capacity;

    public SimpleBitMap(int capacity) {
        this.capacity = capacity;
        // 每个 int 存 32 个 bit
        this.bits = new int[(capacity + 31) / 32];
    }

    public void set(int index) {
        if (index < 0 || index >= capacity) {
            throw new IndexOutOfBoundsException();
        }
        int wordIndex = index >> 5;       // index / 32
        int bitIndex = index & 0x1F;      // index % 32
        bits[wordIndex] |= (1 << bitIndex);
    }

    public boolean get(int index) {
        if (index < 0 || index >= capacity) {
            throw new IndexOutOfBoundsException();
        }
        int wordIndex = index >> 5;
        int bitIndex = index & 0x1F;
        return (bits[wordIndex] & (1 << bitIndex)) != 0;
    }

    public void clear(int index) {
        if (index < 0 || index >= capacity) {
            throw new IndexOutOfBoundsException();
        }
        int wordIndex = index >> 5;
        int bitIndex = index & 0x1F;
        bits[wordIndex] &= ~(1 << bitIndex);
    }

    public int countSetBits() {
        int total = 0;
        for (int word : bits) {
            total += Integer.bitCount(word);
        }
        return total;
    }

    public static void main(String[] args) {
        // 模拟365天签到
        SimpleBitMap signIn = new SimpleBitMap(365);
        signIn.set(0);   // 第1天签到
        signIn.set(10);  // 第11天签到
        signIn.set(100); // 第101天签到

        System.out.println("第1天签到: " + signIn.get(0));     // true
        System.out.println("第2天签到: " + signIn.get(1));     // false
        System.out.println("总签到天数: " + signIn.countSetBits()); // 3
    }
}

十一、面试高频考点

问题 关键要点
IntegerCache 的默认范围 -128 ~ 127,上限可通过 JVM 参数调整
自动装箱用 valueOf 而非 new valueOf 利用缓存,new 绕过缓存
parseInt 为何用负累加 避免 Integer.MIN_VALUE 取负溢出
== 与 equals 在 Integer 中的区别 == 比较引用(缓存内相等,缓存外不等),equals 比较值
bitCount 算法的原理 分治法,逐步合并计数值(变种的 SWAR 算法)
toUnsignedString 的用途 将有符号 int 以无符号形式展示
highestOneBit 的应用场景 HashMap 中计算 tableSizeFor(向上取2的幂)
相关推荐
大鸡腿同学1 小时前
大模型为何总 “胡说八道”?做完 RAG 知识库,我看懂了它的底层逻辑
后端
秋91 小时前
java项目中cpu飙升排查及解决方法
java·开发语言
野生技术架构师1 小时前
牛客网2026最新大厂Java高频面试题精选(附标准答案)
java·开发语言
PH = 71 小时前
JAVA的SPI机制
java·开发语言
一 乐1 小时前
高校实习信息发布网站|基于Spring Boot的高校实习信息发布网站的设计与实现(源码+数据库+文档)
java·数据库·spring boot·后端·论文·毕设·高校实习信息发布网站
安久11 小时前
springboot图片上传至服务器本地保存
后端
weelinking1 小时前
【产品】11_实现后端接口——数据在背后如何流动
java·人工智能·python·sql·oracle·json·ai编程
摇滚侠1 小时前
东方通替换tomcat,实战经验
java
喵个咪2 小时前
选择第三方IAM还是自建权限体系?中小型后台系统权限架构决策指南
后端·架构·go