在一些Java的笔试/面试中,经常会出现Integer的一些问题,我在这里做一个整理和记录。
首先来逐步看Integer的源码:
/**
* A constant holding the minimum value an {@code int} can
* have, -2^31.
*/
@Native public static final int MIN_VALUE = 0x80000000;
/**
* A constant holding the maximum value an {@code int} can
* have, 2^31-1.
*/
@Native public static final int MAX_VALUE = 0x7fffffff;
首先可以看到Integer对象对应的int值在-231到231+1之间,也就是Java中int的范围。
存储Integer对象对应的int值:
/**
* The value of the {@code Integer}.
*
* @serial
*/
private final int value;
然后就是与Integer常见题目相关的这一段重点代码:
private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer[] cache;
static Integer[] archivedCache;
static {
// high value may be configured by property
int h = 127;
String integerCacheHighPropValue =
VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
try {
h = Math.max(parseInt(integerCacheHighPropValue), 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(h, Integer.MAX_VALUE - (-low) -1);
} catch( NumberFormatException nfe) {
// If the property cannot be parsed into an int, ignore it.
}
}
high = h;
// Load IntegerCache.archivedCache from archive, if possible
VM.initializeFromArchive(IntegerCache.class);
int size = (high - low) + 1;
// Use the archived cache if it exists and is large enough
if (archivedCache == null || size > archivedCache.length) {
Integer[] c = new Integer[size];
int j = low;
for(int i = 0; i < c.length; i++) {
c[i] = new Integer(j++);
}
archivedCache = c;
}
cache = archivedCache;
// range [-128, 127] must be interned (JLS7 5.1.7)
assert IntegerCache.high >= 127;
}
private IntegerCache() {}
}
从上述代码中我们可以得到,Integer对象中有一个静态内部类IntegerCache,该类中定义了一个static final的Integer数组名为cache。
并且该内部类中有一个静态代码块,会在加载类的时候将一些数字提前⽣成Integer对象,并缓存在cache数组中,而这个数字范围在源码中为-128~127的闭区间,当然这个是可以通过对JVM的参数修改来实现改变范围的。
核心代码:
if (archivedCache == null || size > archivedCache.length) {
Integer[] c = new Integer[size];
int j = low;
for(int i = 0; i < c.length; i++) {
c[i] = new Integer(j++);
}
archivedCache = c;
}
cache = archivedCache;
可以看到就是在范围内提前new好对应int值的Integer对象,并赋给cache。
再来看看Integer的构造函数:


可以看到new Integer(int x)这种构造方式已经废弃了,Java希望我们用Integer.valueOf(int x)的形式,这里我们再去看看valueOf( )方法的源码。
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
很简单的几行代码,流程其实就是先判断i的大小,如果在缓存的范围之内,那就直接返回IntegerCache内部类中cache数组里的对应int值的Integer对象,如果在缓存值之外,那就new一个Integer对象。
至此我们Integer的关键源码就全部看完了,我们接下来再看一些常见的相关笔试/面试题:
1、Integer对象缓存问题
Integer b = Integer.valueOf(129);
Integer c = Integer.valueOf(129);
Integer d = Integer.valueOf(125);
Integer e = Integer.valueOf(125);
System.out.println(b==c);
System.out.println(d==e);
根据前面的源码讲解,这里应该很好判断了吧,b和c的int值是129,在不修改JVM参数(默认)的情况下,不会被提前缓存,且每次被创建的时候都是new的一个新的Integer对象,而==在比较两个引用类型的时候,比较的是他们的内存地址是否相同。
所以
(b == c) = false ;
(b == c) = false ;
而d和e对应的int值是125,在默认的-128~127范围内,会被IntegerCache内部类中静态代码块提前生成好对应Integer对象,在调用valueOf( )的时候,会直接返回cache数组中的Integer对象,所以d和
e实际取到的是一个对象。
所以在这里
(b==c) = true;
2、Integer拆箱与装箱问题
Integer a = Integer.valueOf(100);
Integer b = 100;
Integer c = 180;
int d = 180;
System.out.println(a==b);
System.out.println(c==d);
这里就要结合Integer装箱和前面的valueOf源码来看了。
首先a与b,一个调用了Integer.valueOf( )函数,一个没有,那他们相等吗?
答案是肯定的,在b的创建过程中,int值100会被自动装箱调用Integer.valueOf( )函数,所以a和b取到的是一个Integer对象。
(a == b) = true;
那c与d呢?
肯定此时有人会自信的写下不相同,因为按照前面的源码分析,180在缓存范围之外,他们应该是不同的。但是这里要注意d并不是引用类型或者说是一个对象,而是一个int基本类型的数值,原本基本类型和引用类型之间是不能用==来进行比较的。
但是因为Integer的自动拆箱,此时c == d会检测到c是一个int基本类型,而d是一个Integer对象,他会把d自动拆箱成一个int值来进行比较,相当与变为(180 ==180),而 == 在比较两个基本类型的时候,是直接比较他们的值的,所以这里的结果也是
(c == d) = true;
本文详细分析了Java中的Integer类的源码,重点关注了Integer对象的缓存机制和valueOf()方法。IntegerCache内部类用于缓存-128到127之间的Integer对象,以提高性能。Integer的构造函数已废弃,推荐使用valueOf()。在面试中常见的Integer相关问题包括对象缓存和装箱拆箱操作。例如,Integer对象在缓存范围内通过valueOf()创建时,比较操作会返回相同结果,反之则会创建新的对象。

772

被折叠的 条评论
为什么被折叠?



