首先我们对两个Integer进行比较

        Integer integer1 = 3;
        Integer integer2 = 3;
        if (integer1 == integer2)
            System.out.println("integer1 == integer2");
        else
            System.out.println("integer1 != integer2");
        Integer integer3 = 300;
        Integer integer4 = 300;
        if (integer3 == integer4)
            System.out.println("integer3 == integer4");
        else
            System.out.println("integer3 != integer4");
上面的程序允许结果如下:
integer1 == integer2
integer3 != integer4
Java 编译器把原始类型自动转换为封装类的过程称为自动装箱(autoboxing),这相当于调用 valueOf 方法
Integer integer1 = 3;
Integer integer2 = Integer.valueOf(3);
其中valueOf源码如下:
public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }
可以看到如果这个数值在cache数组的范围内(low和high之间),就返回cache数组的中的数据,否则产生一个新的Integer值。其源码如下:
 private static class IntegerCache {
        static final int low = -128;
        static final int high;
        static final Integer cache[];
    <span class="token keyword">static</span> <span class="token punctuation">{</span>
        <span class="token comment">// high value may be configured by property</span>
        <span class="token keyword">int</span> h <span class="token operator">=</span> <span class="token number">127</span><span class="token punctuation">;</span>
        <span class="token class-name">String</span> integerCacheHighPropValue <span class="token operator">=</span>
            sun<span class="token punctuation">.</span>misc<span class="token punctuation">.</span>VM<span class="token punctuation">.</span><span class="token function">getSavedProperty</span><span class="token punctuation">(</span><span class="token string">"java.lang.Integer.IntegerCache.high"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>integerCacheHighPropValue <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">try</span> <span class="token punctuation">{</span>
                <span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token function">parseInt</span><span class="token punctuation">(</span>integerCacheHighPropValue<span class="token punctuation">)</span><span class="token punctuation">;</span>
                i <span class="token operator">=</span> <span class="token class-name">Math</span><span class="token punctuation">.</span><span class="token function">max</span><span class="token punctuation">(</span>i<span class="token punctuation">,</span> <span class="token number">127</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token comment">// Maximum array size is Integer.MAX_VALUE</span>
                h <span class="token operator">=</span> <span class="token class-name">Math</span><span class="token punctuation">.</span><span class="token function">min</span><span class="token punctuation">(</span>i<span class="token punctuation">,</span> <span class="token class-name">Integer</span><span class="token punctuation">.</span>MAX_VALUE <span class="token operator">-</span> <span class="token punctuation">(</span><span class="token operator">-</span>low<span class="token punctuation">)</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span> <span class="token keyword">catch</span><span class="token punctuation">(</span> <span class="token class-name">NumberFormatException</span> nfe<span class="token punctuation">)</span> <span class="token punctuation">{</span>
                <span class="token comment">// If the property cannot be parsed into an int, ignore it.</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
        high <span class="token operator">=</span> h<span class="token punctuation">;</span>

        cache <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Integer</span><span class="token punctuation">[</span><span class="token punctuation">(</span>high <span class="token operator">-</span> low<span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
        <span class="token keyword">int</span> j <span class="token operator">=</span> low<span class="token punctuation">;</span>
        <span class="token keyword">for</span><span class="token punctuation">(</span><span class="token keyword">int</span> k <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> k <span class="token operator">&lt;</span> cache<span class="token punctuation">.</span>length<span class="token punctuation">;</span> k<span class="token operator">++</span><span class="token punctuation">)</span>
            cache<span class="token punctuation">[</span>k<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Integer</span><span class="token punctuation">(</span>j<span class="token operator">++</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token comment">// range [-128, 127] must be interned (JLS7 5.1.7)</span>
        <span class="token keyword">assert</span> <span class="token class-name">IntegerCache</span><span class="token punctuation">.</span>high <span class="token operator">&gt;=</span> <span class="token number">127</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">private</span> <span class="token class-name">IntegerCache</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
<span class="token punctuation">}</span>

通常这个范围是-128-127,然而这个范围的最大值是可变的,可以通过-XX:AutoBoxCacheMax=<size>参数去修改这个值,在JVM初始化的时候,这个值被写入sun.misc.VM class系统私有配置文件中,并加载。

这也就是为什么在阿里巴巴Java开发手册的OOP规约中强制使用equals比较两个Integer的值

4.7【强制】所有的相同类型的包装类对象之间值的比较,全部使用 equals 方法比较。 说明: 对于 Integer var=?在-128 至 127 之间的赋值, Integer 对象是在 IntegerCache.cache 产生,会复用已有对象,这个区间内的 Integer 值可以直接使用==进行 判断,但是这个区间之外的所有数据,都会在堆上产生,并不会复用已有对象,这是一个大坑, 推荐使用 equals 方法进行判断
这种缓存行为不仅适用于Integer对象。我们针对所有整数类型的类都有类似的缓存机制。 有 ByteCache 用于缓存 Byte 对象 有 ShortCache 用于缓存 Short 对象 有 LongCache 用于缓存 Long 对象 有 CharacterCache 用于缓存 Character 对象 Byte,Short,Long 有固定范围: -128 到 127。对于 Character, 范围是 0 到 127。除了 Integer 可以通过参数改变范围外,其它的都不行。
作者:时光之刃51y 链接:https://www.jianshu.com/p/b0274de4320e 来源:简书 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。