引入:new Integer(18) 与 Integer.valueOf(18) 有区别吗?有的话,有什么区别?
我们都知道,使用 new 关键字的时候,每次都会新创建一个对象
。但是,Integer.valueOf() 会新创建一个对象吗?
我们来看下面这段代码:
/**
* new Integer与 Integer.valueOf() 的区别
*
* @author qiaohaojie
* @date 2023/3/4 16:23
*/
public class ValueOfMethod {
public static void main(String[] args) {
Integer x = new Integer(18);
Integer y = new Integer(18);
System.out.println(x == y); // false
Integer a = Integer.valueOf(18);
Integer b = Integer.valueOf(18);
System.out.println(a == b); // true
Integer m = Integer.valueOf(300);
Integer n = Integer.valueOf(300);
System.out.println(m == n); // false
}
}
这个结果出现的原因是这样的:
- 第一个结果是 false 是因为两次使用 new 时,创建的是两个不同的对象,也就意味着地址不同,所以结果是 false;
- 第二个结果是 true 是因为 Integer.valueOf() 方法会使用
常量缓存池
中的对象,无论调用多少次,都只会取同一个对象的引用; - 第三个结果是 false 是因为 Integer 内置的 256 个缓存数据是在 -128~127 之间,超过这个范围时会创建新的对象。而 300>127 ,所以 m 和 n 会创建两个新的对象,地址也就不同了,所以结果与第一种是一样的 false。
基本数据类型的包装类除了 Float 和 Double之外,其他六个包装类(Byte、Short、Integer、Long、Character、Boolean)都有对应的常量缓存池:
- Byte:-128~127
- Short:-128~127
- Integer:-128~127
- Long:-128~127
- Character:\u0000~\u007F
- Boolean:true、false
接着我们来扒一下 valueOf() 方法
的源码:
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
我们可以看到,valueOf() 方法内部主要使用了一个静态内部类 IntegerCache
:
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() {}
}
我们都知道,用 static 关键字外加一个大括号括起来的代码被称为静态代码块,通常用来初始化一些静态变量,优先于 main() 方法执行。
在静态代码块中,low 为 -128,也就是缓存池的最小值;high 默认是 127,也就是缓存才能中的最大值,一共是 256 个。
可以在 JVM 启动的时候,通过 -XX:AutoBoxCacheMax=NNN 来设置缓存池的大小,但是不能无限大,最大到 Integer.MAX_VALUE -129。
然后,开始初始化 cache 数组的大小(256),然后开始从下标为 0 开始遍历填充。
最后一行代码 assert IntegerCache.high >= 127 中,assert 是 Java 中的一个关键字,是断言的意思,只是为了方便调试,并不是指发布程序的组成部分。默认情况下,断言是关闭的,我们可以在命令行运行 Java 程序的时候加上 -ea 参数打开断言。
断言的意思可以当成 if…else 语句来理解:
if(假设成立)
{
程序正常运行;
}
else
{
报错&&终止程序!(避免由程序运行引起更大的错误)
}
举个例子:
/**
* new Integer与 Integer.valueOf() 的区别
*
* @author qiaohaojie
* @date 2023/3/4 16:23
*/
public class ValueOfMethod {
public static void main(String[] args) {
int high = 126;
assert high >= 127 ? true : false;
System.out.println(false);
boolean isRight = 1 > 2;
assert isRight : "程序错误";
System.out.println("程序正常");
}
}
输出:
缓存池之所以使用 assert 是因为这样做可以提高程序的整体性能
。因为相比较而言,比如说 Integer,在 128~127 这个范围内的 256 个数字使用的频率相对会高一些。