Integer的valueOf方法与缓存策略

本文探讨了Java中Integer的valueOf方法及其背后的缓存策略。通过一个笔试题的例子,展示了当数值在[-128, 127]范围内时,Integer对象会从缓存中获取,否则会新建对象。IntegerCache类的分析揭示了其low和high的默认值,以及如何影响Integer对象的创建与复用。" 123340542,9740252,C++初学者教程:从Hello World到基本数据类型,"['c++', '开发语言', 'visual studio']

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Integer的valueOf方法与缓存策略

问题的导火索

今天做了牛客网的笔试题,有一道选择题是这样的,给差不多是下面这样的一段代码,问输出是啥~~

public class Test {
    public static void main(String[] args) {

        Integer a = 3;
        Integer b = 3;

        System.out.println(a == b);

        Integer c = 321;
        Integer d = 321;

        System.out.println(c == d);
    }
}

就这个代码,我当时选的是两个true,我觉得3和321并没有区别,也就是说a和b引用的是同一个对象,c和d引用的也应该是同一个对象,这一题怕不是考心理的哦~~~
笔试结束之后我立刻试了一下,发现自己还是太年轻。第一个输出是true,第二个输出是false。当场懵逼,遂单步调试之~~~这里为了方便说明,我就以下面代码展示调试过程:

public class Test {
    public static void main(String[] args) {
        Integer a = 3;
    }
}

调试过程:
在Integer a = 3;前添加断点,程序运行到此处单步调试,由于java的自动装箱机制,编译器会把它编译成Integer a = Integer.valueOf(3);于是会进入valueOf()方法如下:

    @HotSpotIntrinsicCandidate
    public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }

从这个函数可以看出来,如果i在闭区间[IntegerCache.low, IntegerCache.high]范围内,会直接返回一个IntegerCache.cache[]中的一个值。而不在这个范围就会new一个新的Integer对象。

问题到此已经基本明朗了,我们可以猜到3在闭区间[IntegerCache.low, IntegerCache.high]范围内,所以之前代码里的a和b引用的是同一个对象,a==b返回的是true,而321不在那个范围内,即c和d调用valueOf()方法时,会重新new一个对象,在堆里开辟新的空间,c和d引用的自然不是同一个对象了,所以c==d返回的就是false了

IntegerCache.low 与 IntegerCache.high

我们已经能够解释那个问题了,那么到底在哪个范围内是直接引用已有对象,哪个范围内是new新的对象呢以及cache数组存的对象到底是啥?这就关系到IntegerCache.low和IntegerCache.high的值了~~
在return IntegerCache.cache[i + (-IntegerCache.low)];处转入cache的定义,可以进入IntegerCache类,从类的名字可以看出这个类实现了java的Integer类的缓存策略

    private static class IntegerCache {
        static final int low = -128;
        static final int high;
        static final Integer cache[];

        static {
            // high value may be configured by property
            int h = 127;
            String integerCacheHighPropValue =
                VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
            if (integerCacheHighPropValue != null) {
                try {
                    int i = parseInt(integerCacheHighPropValue);
                    i = Math.max(i, 127);
                    // Maximum array size is Integer.MAX_VALUE
                    h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
                } catch( NumberFormatException nfe) {
                    // If the property cannot be parsed into an int, ignore it.
                }
            }
            high = h;

            cache = new Integer[(high - low) + 1];
            int j = low;
            for(int k = 0; k < cache.length; k++)
                cache[k] = new Integer(j++);

            // range [-128, 127] must be interned (JLS7 5.1.7)
            assert IntegerCache.high >= 127;
        }

        private IntegerCache() {}
    }

我们逐行解释一下这个类吧~~
首先前三行给出了low的定义以及high,cache的声明,终于可以明确cache[]是内置的常量数组。我们可以清楚地看到low是-128

        static final int low = -128;
        static final int high;
        static final Integer cache[];

然后是static域给出high和cache[]的定义。

        static {
            // high value may be configured by property
            int h = 127;
            String integerCacheHighPropValue =
                VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
            if (integerCacheHighPropValue != null) {
                try {
                    int i = parseInt(integerCacheHighPropValue);
                    i = Math.max(i, 127);
                    // Maximum array size is Integer.MAX_VALUE
                    h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
                } catch( NumberFormatException nfe) {
                    // If the property cannot be parsed into an int, ignore it.
                }
            }
            high = h;

            cache = new Integer[(high - low) + 1];
            int j = low;
            for(int k = 0; k < cache.length; k++)
                cache[k] = new Integer(j++);

            // range [-128, 127] must be interned (JLS7 5.1.7)
            assert IntegerCache.high >= 127;
        }

String integerCacheHighPropValue = VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
这句话我不认得,看源码没大看懂,猜测是获取high的值后转为了字符串。这里high并没有初始化,所以integerCacheHighPropValue应该就是null的,所以if里面的东西就基本不用看了。看到后面high = h;就知道了high是127。

if里面的东西并没有用到,但为什么要写这段代码呢?
看到注释// high value may be configured by property可以知道high的值实际上是可以进行配置的,这个if段里面的语句也就是为这个服务的了~~~至于怎么配置,这里就不做具体解释了~~~ 主要是我不会呀

然后再来看cache:

        cache = new Integer[(high - low) + 1];
            int j = low;
            for(int k = 0; k < cache.length; k++)
                cache[k] = new Integer(j++);

cache是一个大小为high-low+1,也就是256的Integer对象数组,cache[0]=-128,cache[1]=-127,cache[2]=-126,以此类推,一直到cache[255]=127…

至此,最初的问题已经完全能够解释了,在java里,对于一个int常量i,当执行Integer a = i时,如果-128<=i<=127,那么a会直接引用IntegerCache类内部的静态对象,而i不在这个范围内时,会自动new一个新的对象出来,a会引用这个新的对象。

<think>嗯,用户想了解JavaInteger.parseInt方法的使用注意事项和潜在问题,以及常见错误和解决方法。首先,我得回忆一下这个方法的基本用法。Integer.parseInt是将字符串转换为整数的方法,如果字符串不符合数字格式,就会抛出NumberFormatException。那用户可能在使用时遇到哪些问题呢? 首先,常见的错误应该是传入的字符串包含非数字字符,比如字母或者符号,导致转换失败。比如用户提供的引用[1]中的例子,字符串"123a"无法转换,导致异常。这时候需要捕获异常并处理,或者提前验证输入。 然后,用户可能没有处理空值或者null的情况,直接调用parseInt,这样会导致NullPointerException。比如如果字符串变量是null,调用parseInt就会出错,所以需要先检查是否为null。 还有,字符串可能超出int的范围。比如超过Integer.MAX_VALUE或低于Integer.MIN_VALUE,这时候也会抛出NumberFormatException。这时候需要考虑使用Long.parseLong,或者处理大数的情况。 另外,进制的问题。parseInt可以接受第二个参数指定进制,比如十六进制,但如果字符串中的字符不符合进制要求,比如二进制中出现'2',也会导致错误。比如用户输入的字符串是"1A2"但指定的是十进制,那'A'字符就会引发异常。 然后,用户可能在多线程或静态初始化中使用parseInt,导致类初始化失败,如引用[2]中的例子,静态变量初始化时转换失败,导致ExceptionInInitializerError。这时候需要确保静态初始化的数据是有效的,或者在静态块中处理异常。 还需要注意前导和后导空格的问题,虽然parseInt允许前导空格,但如果有其他空白字符或者后导空格,可能还是会导致错误。比如字符串" 123 "可能没问题,但"123 456"就会出错。这时候可能需要先trim()处理字符串。 此外,用户可能没有正确捕获异常,比如捕获了Exception但没有具体处理,或者直接抛出RuntimeException,如引用[1]中的例子,导致异常信息不够明确,难以调试。正确的做法是捕获具体异常,并给出有意义的错误信息,或者进行适当的恢复处理。 关于使用指南,需要建议用户在使用前进行输入验证,比如使用正则表达式检查是否为有效整数,处理null和空字符串,考虑数值范围,以及正确的异常处理策略,比如返回默认值或者提示用户重新输入。 可能还需要提到不同JDK版本是否有变化,不过一般来说parseInt的行为比较稳定。另外,其他转换方法的比较,比如valueOf,后者会返回Integer对象,而parseInt返回int基本类型,可能需要注意装箱的问题。 总结一下,注意事项包括输入验证、异常处理、进制处理、范围检查,潜在问题主要是NumberFormatException和相关的错误处理不当导致的程序崩溃或难以调试的问题。解决方法包括输入预处理、try-catch块、使用替代方法处理大数等。</think>### Java Integer.parseInt 使用指南常见问题解析 #### 一、方法基础 `Integer.parseInt(String s)` 用于将字符串转换为十进制整数,若输入不合法会抛出 `NumberFormatException`。 扩展方法 `Integer.parseInt(String s, int radix)` 支持指定进制(2-36),例如解析十六进制值: ```java int hexValue = Integer.parseInt("1A", 16); // 输出26 ``` #### 二、使用规范 1. **输入预处理** 验证字符串是否为有效数字格式: ```java if (input != null && input.matches("-?\\d+")) { int num = Integer.parseInt(input); } ``` 2. **数值范围验证** ```java String input = "2147483648"; try { long temp = Long.parseLong(input); // 先转为long类型判断范围 if (temp > Integer.MAX_VALUE) { System.out.println("超出int范围"); } } catch (NumberFormatException e) { // 处理格式错误 } ``` 3. **异常处理原则** 避免直接抛出 `RuntimeException`(如引用[1]的错误示例),应明确异常类型: ```java try { return Integer.parseInt(input); } catch (NumberFormatException e) { throw new IllegalArgumentException("无效的整数格式: " + input, e); } ``` #### 三、六大常见错误场景 1. **非数字字符** ```java Integer.parseInt("12.3"); // 小数点非法 Integer.parseInt("0x1F"); // 需用parseInt("1F",16) ``` 2. **空值/null输入** ```java String input = null; Integer.parseInt(input); // 抛出NullPointerException ``` 3. **超出int范围** ```java Integer.parseInt("2147483648"); // 超过Integer.MAX_VALUE ``` 4. **进制不匹配** ```java Integer.parseInt("101", 2); // 合法二进制 Integer.parseInt("12", 2); // '2'在二进制中非法 ``` 5. **静态初始化错误** 如引用[2]所示,静态变量初始化失败会导致 `ExceptionInInitializerError`: ```java class MyClass { static int num = Integer.parseInt("abc"); // 类加载时直接崩溃 } ``` 6. **特殊符号处理** ```java Integer.parseInt(" 123 "); // 前导/后导空格合法 Integer.parseInt("1,234"); // 千分位符号非法 ``` #### 四、优化实践 | 场景 | 推荐方案 | 代码示例 | |------|----------|----------| | 用户输入处理 | 交互式校验 | 循环提示直至输入合法 | | 批量数据转换 | 流处理+异常收集 | 使用Stream处理并记录错误项 | | 高并发场景 | 预校验+缓存 | 将合法结果存入缓存 | #### 五、扩展替代方案 1. **NumberFormat** 类: ```java NumberFormat.getIntegerInstance().parse("1,234"); // 支持本地化格式 ``` 2. **Scanner** 工具: ```java Scanner scanner = new Scanner("123"); if (scanner.hasNextInt()) { int num = scanner.nextInt(); } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值