Java常见笔试/面试题:Integer

本文详细分析了Java中的Integer类的源码,重点关注了Integer对象的缓存机制和valueOf()方法。IntegerCache内部类用于缓存-128到127之间的Integer对象,以提高性能。Integer的构造函数已废弃,推荐使用valueOf()。在面试中常见的Integer相关问题包括对象缓存和装箱拆箱操作。例如,Integer对象在缓存范围内通过valueOf()创建时,比较操作会返回相同结果,反之则会创建新的对象。

在一些Java的笔试/面试中,经常会出现Integer的一些问题,我在这里做一个整理和记录。
首先来逐步看Integer的源码:

    /**
     * A constant holding the minimum value an {@code int} can
     * have, -2^31.
     */
    @Native public static final int   MIN_VALUE = 0x80000000;

    /**
     * A constant holding the maximum value an {@code int} can
     * have, 2^31-1.
     */
    @Native public static final int   MAX_VALUE = 0x7fffffff;

首先可以看到Integer对象对应的int值在-231到231+1之间,也就是Java中int的范围。

存储Integer对象对应的int值:

    /**
     * The value of the {@code Integer}.
     *
     * @serial
     */
    private final int value;

然后就是与Integer常见题目相关的这一段重点代码:

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

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

            // Load IntegerCache.archivedCache from archive, if possible
            VM.initializeFromArchive(IntegerCache.class);
            int size = (high - low) + 1;

            // Use the archived cache if it exists and is large enough
            if (archivedCache == null || size > archivedCache.length) {
                Integer[] c = new Integer[size];
                int j = low;
                for(int i = 0; i < c.length; i++) {
                    c[i] = new Integer(j++);
                }
                archivedCache = c;
            }
            cache = archivedCache;
            // range [-128, 127] must be interned (JLS7 5.1.7)
            assert IntegerCache.high >= 127;
        }

        private IntegerCache() {}
    }

从上述代码中我们可以得到,Integer对象中有一个静态内部类IntegerCache,该类中定义了一个static final的Integer数组名为cache
并且该内部类中有一个静态代码块,会在加载类的时候将一些数字提前⽣成Integer对象,并缓存在cache数组中,而这个数字范围在源码中为-128~127的闭区间,当然这个是可以通过对JVM的参数修改来实现改变范围的。
核心代码:

if (archivedCache == null || size > archivedCache.length) {
                Integer[] c = new Integer[size];
                int j = low;
                for(int i = 0; i < c.length; i++) {
                    c[i] = new Integer(j++);
                }
                archivedCache = c;
            }
            cache = archivedCache;

可以看到就是在范围内提前new好对应int值的Integer对象,并赋给cache
再来看看Integer的构造函数:
在这里插入图片描述
在这里插入图片描述
可以看到new Integer(int x)这种构造方式已经废弃了,Java希望我们用Integer.valueOf(int x)的形式,这里我们再去看看valueOf( )方法的源码。

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内部类中cache数组里的对应int值的Integer对象,如果在缓存值之外,那就new一个Integer对象。
至此我们Integer的关键源码就全部看完了,我们接下来再看一些常见的相关笔试/面试题:
1、Integer对象缓存问题

Integer b = Integer.valueOf(129);	
Integer c = Integer.valueOf(129);
Integer d = Integer.valueOf(125);
Integer e = Integer.valueOf(125);
System.out.println(b==c);	
System.out.println(d==e);

根据前面的源码讲解,这里应该很好判断了吧,b和c的int值是129,在不修改JVM参数(默认)的情况下,不会被提前缓存,且每次被创建的时候都是new的一个新的Integer对象,而==在比较两个引用类型的时候,比较的是他们的内存地址是否相同。
所以

(b == c) = false ; 

(b == c) = false ;
而d和e对应的int值是125,在默认的-128~127范围内,会被IntegerCache内部类中静态代码块提前生成好对应Integer对象,在调用valueOf( )的时候,会直接返回cache数组中的Integer对象,所以d和
e实际取到的是一个对象。
所以在这里

(b==c) = true;

2、Integer拆箱与装箱问题

Integer a = Integer.valueOf(100);
Integer b = 100;
Integer c = 180;
int d = 180;
System.out.println(a==b);
System.out.println(c==d);

这里就要结合Integer装箱和前面的valueOf源码来看了。
首先a与b,一个调用了Integer.valueOf( )函数,一个没有,那他们相等吗?
答案是肯定的,在b的创建过程中,int值100会被自动装箱调用Integer.valueOf( )函数,所以a和b取到的是一个Integer对象。

(a == b) = true; 

那c与d呢?
肯定此时有人会自信的写下不相同,因为按照前面的源码分析,180在缓存范围之外,他们应该是不同的。但是这里要注意d并不是引用类型或者说是一个对象,而是一个int基本类型的数值,原本基本类型和引用类型之间是不能用==来进行比较的。
但是因为Integer的自动拆箱,此时c == d会检测到c是一个int基本类型,而d是一个Integer对象,他会把d自动拆箱成一个int值来进行比较,相当与变为(180 ==180),而 == 在比较两个基本类型的时候,是直接比较他们的值的,所以这里的结果也是

(c == d) = true; 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

投三分的金闪闪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值