Integer学习

曾经遇见过一道关于Integer的面试题:

Integer a = 180, b = 180;

Integer c=1,d=1;

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

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

输出为:

false

true

一开始也不明白,后来看了下Integer的源码,才知道Integer默认将-128~127之间的整数存储到了一个数组中,我们使用的时候,直接调用数组中数据,而超过这个范围就会重新创建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 static void swap(Integer a, Integer b) {
    Integer temp = a;
    a = b;
    b = temp;
}

一开始,我认为应该是传递的引用,调用后,应该会发生数据值的改变,但事实上数据却并没有发生交换。那就继续看代码吧

/**
 * Returns an {@code Integer} instance representing the specified
 * {@code int} value.  If a new {@code Integer} instance is not
 * required, this method should generally be used in preference to
 * the constructor {@link #Integer(int)}, as this method is likely
 * to yield significantly better space and time performance by
 * caching frequently requested values.
 *
 * This method will always cache values in the range -128 to 127,
 * inclusive, and may cache other values outside of this range.
 *
 * @param  i an {@code int} value.
 * @return an {@code Integer} instance representing {@code i}.
 * @since  1.5
 */
@HotSpotIntrinsicCandidate
public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}

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

看到这里我们也就明白了,我们的数据值保存在value这个私有常量值中,当两个值交换时,因为Integer的自动拆装箱导致传递的是数据值,也就是值传递,因此不会修改原值。想要交换两个Integer对象的值应该通过修改这个value值来实现,因此我们可以通过反射获取这个私有的value属性然后进行修改

 private static void swap1(Integer a, Integer b) {
        try {
            Field field = Integer.class.getDeclaredField("value");
            field.setAccessible(true);
            int temp = a.intValue();
            field.set(a, b.intValue());
            field.set(b,temp);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

测试下,发现还是不对,原来field.set()这个方法传入的是对象, field.set(a, b.intValue())这个方法中,b.intValue()相当于Integer.valueOf(a.intValue()).intValue(),而temp只是int,因此并没有修改b中的value值,好,继续改

 private static void swap1(Integer a, Integer b) {
        try {
            Field field = Integer.class.getDeclaredField("value");
            field.setAccessible(true);
            Integer temp = Integer.valueOf(a.intValue());
            field.set(a, b.intValue());
            field.set(b,temp);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

我们通过反射机制获取Integer属性值value,然后用a的值重新创建一个对象,这样我们传递的就是一个地址值,从而实现真正的交换

注意

以前创建Integer对象的时候,我们都是直接new出来,但是先java已经废弃了这个方法,查看文档发现改为使用Integer.valueOf()方法,查看valueOf方法我们知道,由于-128~127缓存存在,当我们用第一种方式时每次都会产生一个新的实例,而当你使用静态工厂方法时,不一定会产生一个新的实例,所以这样是现在推荐使用valueOf()这个方法的原因吧

总结

通过这个问题的分析,我们主要涉及到Integer的拆装箱、通过反射机制去修改privat final value、Integer的-128~127的缓存,其他的问题我们以后再研究吧

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值