我是靠谱客的博主 热情蛋挞,最近开发中收集的这篇文章主要介绍【JavaSE】深入理解Integer缓存原理1. 前言2. Integer的缓存常量池3. Integer类重写的方法4. Integer的几个比较案例5. 总结,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

文章目录

  • 1. 前言
  • 2. Integer的缓存常量池
  • 3. Integer类重写的方法
  • 4. Integer的几个比较案例
  • 5. 总结

1. 前言

Integer 类在对象中包装了一个基本类型 int 的值。Integer 类对象包含一个 int 类型的字段。

此外,该类提供了多个方法,能在 int 类型和 String 类型之间互相转换,还提供了处理 int 类型时非常有用的其他一些常量和方法。


2. Integer的缓存常量池

Integer源码中,可以找一个一个名为IntegerCache的私有静态内部类,这个类是用来实现Integer的缓存常量池的。

// Integer类中私有的静态类 承载cache的实现
private static class IntegerCache {
static final int low = -128;// 最小支持为-128
static final int high;//最大支持
static final Integer cache[];// 用来装载缓存
常量池
static {
// -128~127 这个范围的整数值是使用最广泛的
int h = 127;
// Java6中可以通过调整JVM启动参数来设置最大值
// 根据应用程序的实际情况 灵活的调整来提高性能
// JVM 的启动参数 -XX:AutoBoxCacheMax=size 修改最大值
String integerCacheHighPropValue =
sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
try {
int i = parseInt(integerCacheHighPropValue);
// 获取较大者
i = Math.max(i, 127);
// 设置最大值不能超过Inter.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
} catch( NumberFormatException nfe) {
// 如果该值配置错误则忽略该参数配置的值,使用默认范围-128~127
}
}
high = h;
// 初始化数组容量为127 + 128 + 1(以默认区间为参考)
cache = new Integer[(high - low) + 1];
int j = low;
// 缓存通过for循环来实现,创建范围内的整数对象并存储到cache数组中
// 程序第一次使用Integer的时候需要一定的额外时间来初始化该缓存
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() {}
}

该缓存常量池的作用,是为了只要值在-128-127之间,无论是采用Integer a=Integer.valueOf(127)还是Integer a=127,都会在缓存常量池中获取到提前创建好的对象。

所以只要值相同,它们获取到的对象是同一个对象,因此地址也相同。

为什么Integer a=127也适用呢?

像上面这样将Integer 类型的a直接赋值给127,Java会通过自动装箱机制,将int类型转化为Integer类型。

自动装箱机制,其实也就是编译期间,编译器自动调用Integer 类中的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源码不难看出,首先会判断参数i是否在缓存常量池的最小值low和最大值high之间,如果是,

就会返回常量池中的对应对象。

否则,就会创建新对象。


3. Integer类重写的方法

public int hashCode() {
return Integer.hashCode(value);
}
public static int hashCode(int value) {
return value;
}

Integer重写了hashCode方法,调用hashCode方法返回值为本身对象的value。

public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
public int intValue() {
return value;
}

Integer重写了equals方法

调用equals方法,首先会判断参数Object obj是否是Integer类型

如果是,则会将obj强转成Integer,然后取其对象中的value,跟自己的value进行判断。

如果不是,则返回false


4. Integer的几个比较案例

两个Integer对象进行比较

public static void main(String[] args) {
Integer a = new Integer(66);
Integer b = new Integer(66);
System.out.println(a == b);
}

因为a和b均为新new出来的对象,并且==比较的是地址,两个new出来的对象永远不可能相等,因此输出false

两个Integer对象使用equal方法进行比较

public static void main(String[] args) {
Integer a = new Integer(66);
Integer b = new Integer(66);
System.out.println(a.equals(b));
}

上面有说过使用equal方法,如果两个比较的对象均为Integer,则比较它们的value是否相等,很明显,它们的value相等,所以是true

基本类型和Integer类型 通过 == 比较

public static void main(String[] args) {
Integer a = new Integer(66);
int b = 100;
System.out.println(a == b);
}

这里,基本类型和Integer类型比较,Java会先自动进行拆箱操作,也就是将包装类型转化为基本类型,然后再进行比较,所以比较的是两个int值是否相同,答案是true

在缓存范围内的比较

public static void main(String[] args) {
Integer a = 66;
Integer b = 66;
System.out.println(a == b);
}

对于这种直接将两个int类型赋值给Integer,Java会先进行自动装箱,也就是调用valueOf方法。

由于66在[-127,128]范围内,也就是默认的缓存范围,所以这里不会新创Integer对象,而是生成的对象引用都会指向Integer内部的常量池中对应的值的对象。所以两个对象为同一对象。因此答案是true

在缓存范围外的比较

public static void main(String[] args) {
Integer a = 128;
Integer b = 128;
System.out.println(a == b);
}

同样的,Java会进行装箱操作,但是由于值不在[-127, 128]范围内,因此valueOf方法会返回一个new Integer(i);,因此两个对象并不是指向常量池对应的值的对象,故不是同一对象。答案是false

new生成的Integer对象与直接赋值的Integer对象的比较

public static void main(String[] args) {
Integer a = new Integer(66);
Integer b = 66;
System.out.println(a == b);
System.out.println(a.equals(b));
}

首先,a是new出来的对象,而b是指向Integer内部的常量池中对应的值的对象。

两者明显不是一个对象,只是两个对象的value相同而已。

所以答案是falsetrue


5. 总结

首先,不仅仅是Integer类型有缓存常量池这个说法。

Byte,Short,Integer,Long,Character都有缓存常量池。

  1. Byte,Short,Integer,Long为 缓存范围 -128 到 127
  2. Character缓存范围为 0 到 127
  3. 只有Integer缓存范围可以改变

其次,开发中应该尽量避免多次装箱开箱操作。

int值直接存放于内存栈中,虽然数值操作不是原子性的,但是在单线程的存取操作中,开销小,所以速度快很多,不像Integer**,还需要牵扯对象头的内存存储以及其他操作,更加的消耗性能**。


最后

以上就是热情蛋挞为你收集整理的【JavaSE】深入理解Integer缓存原理1. 前言2. Integer的缓存常量池3. Integer类重写的方法4. Integer的几个比较案例5. 总结的全部内容,希望文章能够帮你解决【JavaSE】深入理解Integer缓存原理1. 前言2. Integer的缓存常量池3. Integer类重写的方法4. Integer的几个比较案例5. 总结所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(55)

评论列表共有 0 条评论

立即
投稿
返回
顶部