Java整数缓存:为什么Integer.valueOf(127)== Integer.valueOf


在一次采访中,我的一个朋友被问到:如果我们有两个Integer对象,Integer a = 127; Integer b = 127;为什么 当两个对象都持有两个单独的对象时a == b求值true?在本文中,我将尝试回答这个问题并解释答案。

您可能还会喜欢: 整数的内部缓存

简短答案 这个问题的简短答案是,直接将int文字分配给Integer引用是自动装箱概念的一个示例,其中,到对象转换代码的文字值由编译器处理,因此在编译阶段,编译器将转换Integer a = 127;为Integer a = Integer.valueOf(127);。

所述Integer类维护内部IntegerCache为此,默认情况下,从范围的整数-128 to 127Integer.valueOf()方法返回从该高速缓存的上述范围对象。因此a == b返回true,因为a并且b两者都指向同一个对象。

长答案 为了理解简短的答案,让我们首先了解Java类型,Java中的所有类型都归为两类

原语类型:有8种原语类型(byte, short, int, long, float, double, char,boolean在Java,它直接持有二进制位的形式它们的值)。 例如,int a = 5; int b = 5;在这里a和b直接持有的5二进制值,如果我们试图比较a和b使用a == b,我们实际上比较5 == 5,返回true。 引用类型:除基本类型外,所有其他类型都属于引用类型的类别,例如,类,接口,枚举,数组等,引用类型保存对象的地址,而不是对象本身。 例如Integer a = new Integer(5); Integer b = new Integer(5),在这里,a和b不成立的二进制值5,而不是ab拥有两个不同的对象其中两个对象包含的值的内存地址5。因此,如果我们尝试比较ab使用a == 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();

现在,如果我们创建两个整数对象ab,尝试使用equals运算符进行比较==,则将得到结果,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

但是,如果我们将值赋给127两者a,b并尝试使用相等运算符比较它们==,我们将得到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

从代码中可以看到,我们为和分配了不同的对象ab但是a == b只有当a和b都指向相同的对象时,才可以返回true 。

那么,比较如何返回true?这里到底发生了什么?是a和b指向同一个对象?

好的,到目前为止,我们知道代码Integer a = 127;是自动装箱的示例,并且编译器会自动将此行转换为Integer a = Integer.valueOf(127);

因此,正是该Integer.valueOf()方法返回了这些整数对象,这意味着该方法必须在后台进行某些操作。

并且,如果我们看一下Integer.valueOf()method的源代码,我们可以清楚地看到,如果传递的int文字i大于IntegerCache.low和小于,IntegerCache.high ,则该方法将从返回Integer对象IntegerCache。默认值IntegerCache.lowIntegerCache.high是-128和127分别。

换句话说,如果传递的 文字大于和小于,则Integer.valueOf()方法从内部返回Integer对象,而不是创建和返回新的整数对象。IntegerCacheint-128127

/**
 * 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,总是得到相同的对象的原因。

integer-cache-src-code.jpeg

当类由于加载到内存时,首次使用时会初始化缓存static block。缓存的最大范围可以由-XX:AutoBoxCacheMaxJVM选项控制。

此缓存行为仅不适用于Integer对象。类似Integer.IntegerCache,我们也有ByteCacheShortCacheLongCacheCharacterCacheByte,Short,Long,Character分别。

Byte, Short和 Long的固定缓存范围是-127到127(包括),但对于 Character,范围是0到127(包括)。只能通过参数为Integer修改范围,而不能为其他参数修改范围。


原文链接:http://codingdict.com