要理解什么是“128陷阱”,首先来看一段代码:
public static void main(String... strings) {
 
    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");
 
}从代码上看,两个if判断的执行逻辑相同,结果理应相同,而如果你有一定的Java基础,不难得出两个判等操作的结果应该都是false。因为Integer是一个包装类,而“==”进行判断非基础类型变量大小的逻辑是比较其地址是否相同。但是实际运行结果呢?

造成这种“矛盾”的原因,就是所谓的“128陷阱”。
要了解“128陷阱”,首先我们要知道什么是“基本数据类型”及其对应的“包装类”。
我们知道,Java语言中,有8种基本数据类型,但是Java作为一门“面向对象”的语言,使用不属于“对象”的数据类型有时会带来很多麻烦。比如,当我们使用集合类时,我们必须在集合中放入Object类型的元素,也就是我们不能直接把int、double等类型的元素放到集合里。这时候,它们的包装类就产生了。基本数据类型和其对应的包装类型相互转换的过程,就是所谓的“装箱”“拆箱”操作。
| 基本数据类型 | 对应的包装类型 | 
| byte | java.lang.Byte | 
| short | java.lang.Short | 
| int | java.lang.Integer | 
| long | java.lang.Long | 
| float | java.lang.Float | 
| double | java.lang.Double | 
| boolean | java.lang.Boolean | 
| char | java.lang.Character | 
为了减轻开发人员的压力,Java为我们提供了自动拆装箱的功能,例如如下代码的写法是不会报错的。
Integer i =10;  //装箱
int b= i;  //拆箱而就是这种自动拆装箱的功能,为我们带来了“128陷阱”。在Java 5中,Integer和int对象通过使用相同的对象引用实现了缓存和重用,从而达到节省内存、提高性能的目的。
我们来看下面这段代码,运行结果已经注释在上面了。
int f = 128;
int f1 = 128;
int g = 127;
Integer g0 = 127;
Integer g1 = 127;
Integer h = 128;
Integer h1 = 128;
        
System.out.println(f == f1); //t
System.out.println(g == g1);    //t
System.out.println(g0 == g1);    //t
System.out.println(h == h1); //f
System.out.println(h.equals(h1)); //t大多数情况下,使用“==”进行比较时,如果比较的是基本数据类型,那么会直接比较值是否相同,即第8行代码;如果比较的是引用类型,那么则会比较地址是否相同,如第10行代码。因此对引用类型的比较我们通常会使用equals()来进行,即第12行代码。这些都没有问题。但是可以看到第11行代码同样是引用类型之间的比较,但是却得到了true的结果。这就是128陷阱。
事实上,在valueOf()方法中,当整数值在-128~127之间时,数值都存储在缓存中,当需要自动装箱时,如果数字在该范围内,就会直接使用缓存中的对象,而不会再重新创建对象,因此相同的值的数据会有同样的地址。在Java 6中,我们可以使用java.lang.Integer.IntegerCache.high来根据实际情况设值该范围的最大值。
以上就是从原理层面对“128陷阱”产生的原因进行的解释,接下来我们从底层源码上看。
public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }可以看到,当数值介于IntegerCache.low和IntegerCache.high之间时,就会直接从IntegerCache.cache中获取对象,否则才会创建一个新对象。
而在IntegerCache中,定义了low的值等于-128,而最大值默认为127,开发人员可以通过AutoBoxCacheMax自行修改。 缓存通过for循环实现,存储在一个整数数组中。这个缓存会在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 =
                sun.misc.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() {}        当然,这种缓存行为不仅适用于Integer对象。事实上这种机制存在于所有整数类型的类中,其中Byte、Short、 Long的固定范围均为-128 =到127且不可更改。


















![[240709] X-CMD 发布 v0.3.15:新增 uname、coin、df 和 uptime 模块;优化非 Posix Shell](https://i-blog.csdnimg.cn/direct/d9fb2279657c431ca5650c3964b5c723.png#pic_center)
