在一次采访中,我的一个朋友被问到如果我们有两个Integer对象, Integer a = 127; Integer b = 127; Integer a = 127; Integer b = 127; 为什么当a == b都持有两个单独的对象时,其值为true ? 在本文中,我将尝试回答这个问题,并尝试解释答案。 
简短答案
 这个问题的简短答案是,将int常量直接分配给Integer引用是自动装箱概念的一个示例,在该示例中,由编译器处理到对象转换代码的常量值,因此在编译阶段,编译器将Integer a = 127;转换为Integer a = 127; Integer a = Integer.valueOf(127); 。 
 Integer类为内部整数维护一个内部IntegerCache,这些整数默认范围为-128 to 127并且Integer.valueOf()方法从该缓存中返回上述范围的对象。 因此a == b返回true,因为a和b都指向同一个对象。 
长答案
为了理解简短的答案,让我们首先了解Java类型,Java中的所有类型都分为两类
-  基本类型: Java中有8种基本类型(字节,短型,整型,长型,浮点型,双精度型,字符型和布尔型),它们直接以二进制位的形式保存其值。 
 例如int a = 5; int b = 5;int a = 5; int b = 5;这里a和b直接持有的5二进制值,如果我们试图比较a和b使用a == b我们实际上是在比较5 == 5返回true。
-  引用类型:除基本类型外,所有其他类型都位于引用类型的类别下,例如类,接口,枚举,数组等,引用类型保存对象的地址,而不是对象iteslf。 
 例如,Integer a = new Integer(5); Integer b = new Integer(5)Integer a = new Integer(5); Integer b = new Integer(5),此处a和b不保存二进制值5而是a和b保存两个单独对象的内存地址,其中两个对象都包含值5。 因此,如果尝试使用a == b,比较a和ba == b,则实际上是在比较这两个单独的内存地址,因此我们得到false,要对a和b执行实际相等,需要执行a.euqals(b)。 引用类型又分为4类: 强引用,软引用,弱引用和幻像引用 。
 
而且我们知道Java为所有原始类型提供包装器类,并支持自动装箱和自动拆箱。
// Example of auto-boxing, here c is a reference type
Integer c = 128; // Compiler converts this line to Integer c = Integer.valueOf(128); // Example of auto-unboxing, here e is a primitive type
int e = c; // Compiler converts this line to int e = c.intValue(); 现在,如果我们创建两个整数对象a和b,并尝试使用相等运算符==进行比较,则将得到false因为两个引用都持有不同的对象 
Integer a = 128; // Compiler converts this line to Integer a = Integer.valueOf(128);
Integer b = 128; // Compiler converts this line to Integer b = Integer.valueOf(128);System.out.println(a == b); // Output -- false 但是,如果我们为a和b都分配值127并尝试使用等于运算符==进行比较,那么为什么会true ? 
Integer a = 127; // Compiler converts this line to Integer a = Integer.valueOf(127);
Integer b = 127; // Compiler converts this line to Integer b = Integer.valueOf(127);System.out.println(a == b); // Output -- true 正如我们在代码中看到的那样,我们为a和b分配了不同的对象,但是只有当a和b都指向同一个对象时, a == b才能返回true。 
 那么比较如何返回true? 这里到底发生了什么? 是a和b指向相同的对象? 
 到目前为止,我们知道代码Integer a = 127; 是自动装箱的示例,编译器自动将此行转换为Integer a = Integer.valueOf(127); 。 
 因此,正是Integer.valueOf()方法返回这些整数对象,这意味着该方法必须在幕后进行某些操作。 
 并且,如果我们看一下Integer.valueOf()方法的源代码,我们可以清楚地看到,如果传递的int文字i大于IntegerCache.low且小于IntegerCache.high则该方法从IntegerCache返回Integer对象。 IntegerCache.low和IntegerCache.high默认值分别是-128和127 。 
 换句话说而不是创建和retruning新的整数对象, Integer.valueOf()方法返回整数从内部对象IntegerCache如果传递的INT字面大于 
 -128且小于127 。 
/*** 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*/public static Integer valueOf(int i) {if (i >= IntegerCache.low && i <= IntegerCache.high)return IntegerCache.cache[i + (-IntegerCache.low)];return new Integer(i);}Java缓存落入-128到127范围内的整数对象,因为该整数范围在日常编程中被大量使用,从而间接节省了一些内存。
 如您在下图中所看到的, Integer类维护一个内部静态IntegerCache类,该类充当缓存并保存从-128到127的整数对象,这就是为什么当我们尝试获取127整数对象时总是得到相同的对象。 
  
 当类由于static block而被加载到内存时,首次使用时将初始化缓存。 高速缓存的最大范围可以由-XX:AutoBoxCacheMax JVM选项控制。 
 此缓存行为仅适用于Integer对象,类似于Integer.IntegerCache我们还有ByteCache , ShortCache , LongCache , Byte CharacterCache , Short , 
 Long , Character 。 
Byte,Short和Long具有固定的缓存范围,介于–127到127(含)之间,而Character的范围是0到127(含)之间。 只能通过参数对Integer修改范围,而不能对其他参数进行修改。
您可以在此Github存储库中找到本文的完整源代码,请随时提供宝贵的反馈。
翻译自: https://www.javacodegeeks.com/2018/11/integer-cache-integer-valueof127-true.html