常量缓存与integer比较_面试官:说说Integer缓存范围

本文主要大致思路为:

不管从工作中还是面试,这篇文章都应该好好看完,本人认为是非常有用的。

案例

Integer是基本类型int的封装类。平时不管是入坑多年的小伙伴还在入坑路上的小伙伴,都应该知道的使用频率是相当高。

下面模仿订单支付,做了一个订单支付状态枚举类PayStatusEnum

public class IntegerDemo {

public static void main(String[] args) {

Integer a = new Integer(8);

Integer b = Integer.valueOf(8);

Integer c = 8;

System.out.println(a.equals(b));

System.out.println(a.equals(c));

System.out.println(b.equals(c));

System.out.println(a == b);

System.out.println(a == c);

System.out.println(b == c);

}

}

结果输出什么?

把上面代码中的8改成128后,又输出什么?

public class IntegerDemo {

public static void main(String[] args) {

Integer a = new Integer(128);

Integer b = Integer.valueOf(128);

Integer c = 128;

System.out.println(a.equals(b));

System.out.println(a.equals(c));

System.out.println(b.equals(c));

System.out.println(a == b);

System.out.println(a == c);

System.out.println(b == c);

}

}

答案慢慢道来。

解析案例

Integer整体阅览

构造方法

private final int value;

public Integer(int value) {

this.value = value;

}

太简单了,没什么可讲的。

valueOf()方法

public static Integer valueOf(String s) throws NumberFormatException {

return Integer.valueOf(parseInt(s, 10));

}

//@HotSpotIntrinsicCandidate 这个注解是JDK9才引入的//HotSpot 虚拟机将对标注了@HotSpotIntrinsicCandidate注解的方法的调用,//替换为直接使用基于特定 CPU 指令的高效实现。这些方法我们便称之为 intrinsic。public static Integer valueOf(int i) {

//如果i在low和high之间就使用缓存 if (i >= IntegerCache.low && i <= IntegerCache.high){

return IntegerCache.cache[i + (-IntegerCache.low)];

}

return new Integer(i);

}

上面valueOf()方法中用到了IntegerCache,下面我们来聊聊。

IntegerCache

下面是IntegerCache源码和部分注释:

/*** Cache to support the object identity semantics of autoboxing for values between* -128 and 127 (inclusive) as required by JLS.* JLS协议要求缓存在-128到127之间(包含边界值)** The cache is initialized on first usage.* 程序第一次使用Integer的时候* The size of the cache may be controlled by the {@code -XX:AutoBoxCacheMax=} option.* JVM 的启动参数 -XX:AutoBoxCacheMax=size 修改最大值* During VM initialization, java.lang.Integer.IntegerCache.high property* may be set and saved in the private system properties in the* sun.misc.VM class.* 可以通过系统属性来获得:-Djava.lang.Integer.IntegerCache.high=*/

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");

//如果有配置-XX:AutoBoxCacheMax= if (integerCacheHighPropValue != null) {

try {

int i = parseInt(integerCacheHighPropValue);

//和127进行比较,谁大用谁 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. // 如果该值配置错误则忽略该参数配置的值,使用默认范围-128~127 }

}

high = h;

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++);

}

//无论如何,缓存的最大值肯定是大于等于127 assert IntegerCache.high >= 127;

}

//私有的构造方法,因为所有的属性均属于类常量 private IntegerCache() {}

}

整个静态块:

那么,如何设置java.lang.Integer.IntegerCache.high的值呢?

The size of the cache may be controlled by the {@code -XX:AutoBoxCacheMax=} option.

注释中已经说清楚,可以使用-XX:AutoBoxCacheMax=设置。

写个demo来debug看看

public class IntegerDemo {

public static void main(String[] args) {

Integer a = 8;

Integer b =Integer.valueOf(8);

System.out.println(a.equals(b));

System.out.println(a == b);

}

}

设置`-XX:AutoBoxCacheMax`=100

开始debug

看看high的值

是127,那就对了,因为上面

设置`-XX:AutoBoxCacheMax`=130

开启debug模式

注意:low=-128是不会变的,整个缓存初始化过程并没有对low进行修改,再说low是常量。

-XX:AutoBoxCacheMax最大能设置成多大?

因为Integer的最大值是2147483647 ,所以我们这里使用这个值试试,

开始debug,直接报OOM了

为什么会OOM呢?

如果-XX:AutoBoxCacheMax没有设置值,那么对应数组是这样的。

equals()方法

上面的案例中有equals方法,这里把这个方法也拿出来聊聊

private final int value;

public boolean equals(Object obj) {

if (obj instanceof Integer) {

//这里比较的是两个int类型的值 return value == ((Integer)obj).intValue();

}

//obj不是Integer类型直接返回false return false;

}

回到上面的案例中

当我们使用equals方法比较两个对象是否相等的时候其实就是比较他们的value值。

所以不管是128还是8,equals后肯定都是true。

当引用类型使用==进行比较的时候,此时比较的是两个引用的对象的地址,是不是同一个。

public class IntegerDemo {

public static void main(String[] args) {

Integer a = new Integer(8);

Integer b = Integer.valueOf(8);

Integer c = 8;

System.out.println(a.equals(b));

System.out.println(a.equals(c));

System.out.println(b.equals(c));

System.out.println(a == b);

System.out.println(a == c);

System.out.println(b == c);

}

}

我们看看器class文件中的字节码;

本地变量表

每个本地变量赋值的过程

这里我们可以得出一个结论:

Integer c =8;就是Integer c = Integer.valueOf(8);

上面Integer b = Integer.valueOf(8);,那就说明变量b和c都是使用Integer.valueOf()获取到的。

valueOf方法中

-XX:AutoBoxCacheMax不设置

上面关于IntegerCache的low和high已经进行了说明,low永远是-128,所以当我们没有设置

-XX:AutoBoxCacheMax 的值的时候,这时候 high=127。

当Integer.valueOf(8);的时候,就会进入上面代码中的if中。然后从IntegerCache中的数组cache中获取。

但是IntegerCache中的cache数组是个常量数组。

言外之意,就是一旦给这个数组cache赋值后,就不会变了。

Integer b = Integer.valueOf(8);和Integer c=8;

b和c不就是都指向同一个引用地址吗?

所以 b==c为true;

但是Integer b=Integer.valueOf(128);

此时就不进入if中,而是直接new一个Integer对象

所以此时

Integer b=Innteger.valueOf(128) ;和Integer c = 128;

都会各自new 一个Integer对象,

此时的b==c为false。

这里也就是网上很多文章也就说到这里,就是比较当前int i 这个i是不是在-128到127范围之内。

-XX:AutoBoxCacheMax设置为130

如果我们把-XX:AutoBoxCacheMax设置为130。那么上面

Integer b=Innteger.valueOf(128) ;和Integer c = 128;

也会进入if条件中。

最后b==c为true。

如何避坑

Integer是基本类型int的封装类,那么在平常使用的时候需要注意几点:

1,如果使用Integer,注意Integer的默认是null,容易引起空指针异常NullPointerException。

2,如果使用int类型,注意int类型的初始值是0,很多设计某某状态时,很喜欢用0作为某个状态,这里要小心使用。

3,另外从内存使用层面来讲,int是基本数据类型,只占用4个字节,Integer是一个对象,当表示一个值时Integer占用的内存空间要高于int类型,从节省内存空间考虑,建议使用int类型(建议了解一下Java对象内存布局)。

4,Integer使用的时候,直接赋值,Integer c = 8,不要new Integer(8)。因为直接赋值就是Integer.valueOf方法使用缓存,没必要每次都new一个新对象,有效提高内存使用。

5,如果系统中大量重复的使用比127大的数,建议JVM启动的时候为-XX:AutoBoxCacheMax=size 适当的大小,提升内存使用效率(但是也不能太大,上面我们已经演示了可能出现OOM)。

面试题

面试题1

Integer num1 = new Integer(10);

Integer num2 = new Integer(10);

System.out.println(num1.equals(num2));

System.out.println(num1 == num2);

面试题2

Integer num3 = 100;

Integer num4 = 100;

System.out.println(num3.equals(num4));

System.out.println(num3 == num4);

面试题3

Integer num5 = 1000;

Integer num6 = 1000;

System.out.println(num5.equals(num6));

System.out.println(num5 == num6);

把上面看完了,再回头来看看这种面试题,还难吗?

如果在面试中遇到面试题3,可以适当反问一下面试官是否有对缓存范围进行调整,或许某些面试官都会懵逼。

赤裸裸的吊打面试官。

总结

1.引用类型的==是比较对应的引用地址。

2.Integer中使用的默认缓存是-128到127。但是可以在JVM启动的时候进行设置。

3.Integer b=Integer.valueOf(8);和Integer b=8;是一样的效果。

4.Integer.valueOf()方式,比较是否在缓存范围之内,在就直接从缓存中获取,不在new一个Integer对象。

5.每次使用new来创建Integer对象,是用不到IntegerCache缓存的。

6.Integer中的使用缓存的方式也可以理解为享元模式。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
use global use component_prameter use constant use time_control use LOCAL_RESM implicit none character*20 :: Para_Inlst01,Para_Inlst02,Para_Inlst03 character*20 :: Para_Inlst04,Para_Inlst05,Para_Inlst06,Para_Inlst07 real*8 :: DX_3DV_Input(100),DY_3DV_Input(100),DZ_3DV_Input(100) real*8 :: VELX_3DV_Input,VELY_3DV_Input,VELZ_3DV_Input real*8 :: ANGX_3DV_Input,ANGY_3DV_Input,ANGZ_3DV_Input integer :: CV_Structure_x,CV_Structure_y,CV_Structure_z real*8 :: Gama_CV,Gama_X,Gama_Y,Gama_z integer :: AQCVIN_x,AQCVIN_y,AQCVIN_z real*8 :: AQQ_Input,AQT_Input, AQH_Input character*20 :: INDEX_ISIDE_3DCV, INDEX_OSIDE_3DCV real*8 temp_tterm integer:: N3DV, I3DV integer:: I3DJX, I3DJY, I3DJZ integer:: NX_3DJX,NY_3DJX,NZ_3DJX integer:: NX_3DJY,NY_3DJY,NZ_3DJY integer:: NX_3DJZ,NY_3DJZ,NZ_3DJZ integer:: INCV_X,INCV_Y,INCV_Z integer:: OUTCV_X,OUTCV_Y,OUTCV_Z integer:: Nin_3Dpool,Nout_3Dpool integer:: In_3DPool_X(1000), In_3DPool_Y(1000),In_3DPool_Z(1000) integer:: Out_3DPool_X(1000), Out_3DPool_Y(1000),Out_3DPool_Z(1000) integer:: In_3DV,Out_3DV character*20 :: Connect_InName,Connect_OutName character*20 :: InName_Con(1000),OutName_Con(1000) character*20 :: Index_Oside_3DCV_INPUT(1000), Index_Iside_3DCV_INPUT(1000) integer:: IO_3DPool_X(1000), IO_3DPool_Y(1000), IO_3DPool_Z(1000) character*20 :: Index_IOside_3DCV_INPUT(1000), IOName_Con(1000) integer:: IO_3DV integer:: IO_Cv_X,IO_Cv_Y,IO_Cv_Z ,NIO_3Dpool character*20 :: Index_IOside_3DCV, Connect_IOName integer:: NX_3DV_Input,NY_3DV_Input,NZ_3DV_Input integer:: NTOTAL_3DV,NTOTAL_3DJX,NTOTAL_3DJY,NTOTAL_3DJZ integer:: IZ_3DV ,IX_3DV ,IY_3DV integer:: IZ_3DJX ,IX_3DJX ,IY_3DJX integer:: IZ_3DJY ,IX_3DJY ,IY_3DJY integer:: IZ_3DJZ ,IX_3DJZ ,IY_3DJZ integer:: IX,IY,IZ integer:: IJUNC
06-10

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值