目录

  • 案列
    • 案列分析
      • 自动装箱机制
      • 是否是同一个对象
      • 源码
    • 为什么这么设计
  • `Java` 自动装箱与自动拆箱
    • 自动装箱
    • 自动拆箱
  • 其它具有缓存机制的基本类型
  • `Integer` 的实例化方式
    • `Integer` 的构造方法
    • `Integer` 的实例化方式
  • 经典案列
    • 案列一
    • 案列分析
    • 案列二
    • 案列分析

案列

public class IntegerTest {public static void main(String[] args) {for (int i = 0; i < 150; i++) {Integer a = i;Integer b = i;System.out.println(i + ":" + (a == b));}}
}结果:从 0 到 127 均显示两个变量相等,而从 128 开始不相等?
0:true
1:true
2:true
3:true
......
126:true
127:true
128:false
129:false
130:false
......

案列分析

自动装箱机制

Integer a = 1;
  • 变量 aInteger 类型,而 1int 类型,且 Integerint 之间并无继承关系,按照 Java 的一般处理方法,这行代码应该报错
  • 但因为自动装箱机制的存在,在将 int 类型的值赋给 Integer 类型变量(引用变量)时,Java 会自动将 int 类型转换为 Integer 类型,即
Integer a = Integer.valueOf(1);

valueOf() 方法返回一个 Integer 类型的引用变量。这就是 int 的自动装箱

是否是同一个对象

最开始的案列,每次循环时,Integer a = iInteger b = i 都会触发自动装箱机制,而自动装箱机制会将 int 转换 Integer 类型变量(引用变量)并返回,Integer 类是 int 类型数据的包装类;我们知道 Java 中两个 new 出来的对象,因为是不同的实例,所以无论如何 == 都会返回 fasle

// 返回 false
new Integer(1) == new Integer(1);

那么上述案列中 Integer a = iInteger b = i 自动装箱产生的引用变量 ab 就不应该时同一个对象了,那么 == 的结果应该是 false

128 以上为 false 容易理解,但为何 0127 时返回 true了呢? == 返回 true 的唯一情况是比较的两个对象为同一个对象,那不妨把例子中 ab 的内存地址都打印出来看看

public class IntegerTest {public static void main(String[] args) {for (int i = 0; i < 150; i++) {Integer a = i;Integer b = i;// identityHashCode() 方法可以理解为输出对应变量的内存地址System.out.println(a + ":" + System.identityHashCode(a) + "  " + b+ ":" + System.identityHashCode(b));}}
}结果:
0:140435067  0:140435067
1:1450495309  1:1450495309
2:1670782018  2:1670782018
3:1706377736  3:1706377736
......
120:1296064247  120:1296064247
121:1637070917  121:1637070917
122:780237624  122:780237624
123:205797316  123:205797316
124:1128032093  124:1128032093
125:1066516207  125:1066516207
126:443308702  126:443308702
127:935044096  127:935044096
128:396180261  128:625576447
129:1560911714  129:939047783
130:1237514926  130:548246552
......

竟然从 0127 不同时候自动装箱得到的是同一个对象!从 128 开始才是正常情况

源码

0127 不同时候自动装箱得到的是同一个对象就只能有一种解释:自动装箱并不一定 new 出新的对象。既然自动装箱涉及到的方法是 Integer.valueOf(),看看其源码

public static Integer valueOf(int i) {assert IntegerCache.high >= 127;// 当前值在缓存数组区间段,则直接返回该缓存值if (i >= IntegerCache.low && i <= IntegerCache.high)return IntegerCache.cache[i + (-IntegerCache.low)];// 否则创建新的Integer实例return new Integer(i);}
}
  • 直接说明了 -128127 之间的值都是直接从缓存中取出的。如果 int 型参数 iIntegerCache.lowIntegerCache.high 范围内,则直接由 IntegerCache 返回;否则 new 一个新的对象返回。而 IntegerCache.low = -128IntegerCache.high = 127
private static class IntegerCache {static final int low = -128;static final int high;static final Integer cache[];// IntegerCache初始化时,缓存数值为-128-127的Integer实例(默认是从-128到127)。static {// high的值可由属性配置int h = 127;String integerCacheHighPropValue =sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");if (integerCacheHighPropValue != null) {int i = parseInt(integerCacheHighPropValue);i = Math.max(i, 127);// Maximum array size is Integer.MAX_VALUEh = Math.min(i, Integer.MAX_VALUE - (-low) -1);}high = h;cache = new Integer[(high - low) + 1];int j = low;// 填充缓存数组for(int k = 0; k < cache.length; k++)cache[k] = new Integer(j++);}private IntegerCache() {}
}
  • 在其 static 块中生成了 -128127 区间的 Integer 类型引用变量,缓存在 cache[] 中,对于 -128127 之间的 int 类型,返回的都是同一个 Integer 类型对象即 final Integer cache[]
  • 注意,这里的创建不包括用 new 创建,new 创建对象不会复用缓存实例

整个工作过程就是:Integer.class 在装载(Java 虚拟机启动)时,其内部类型 IntegerCachestatic 块即开始执行,实例化并暂存数值在 -128127 之间的 Integer 类型对象。当自动装箱 int 型值在 -128127 之间时,即直接返回 IntegerCache 中暂存的 Integer 类型对象

  • 缓存上界 high 可以通过 jvm 参数 -XX:AutoBoxCacheMax=size 指定,取指定值与 127 的最大值并且不超过 Integer 表示范围
  • 下界不能指定,只能为 -128

为什么这么设计

是出于效率考虑,因为自动装箱经常遇到,尤其是小数值的自动装箱;而如果每次自动装箱都触发 new,在堆中分配内存,就显得太慢了;所以不如预先将那些常用的值提前生成好,自动装箱时直接拿出来返回。哪些值是常用的?就是 -128127

Java 自动装箱与自动拆箱

自动装箱和拆箱由编译器完成,编译器会在编译期根据语法决定是否进行装箱和拆箱操作

自动装箱

自动装箱:把基本类型用它们对应的引用类型包装起来,使它们具有对象的特质,可以调用 toString()、hashCode()、getClass()、equals() 等方法

例如

Integer a = 3;

编译器内部会调用 valueOf(int i) 这个方法,valueOf(int i) 返回一个指定 Integer 对象,那么就变成这样

Integer a = 3;  ---> Integer a = Integer.valueOf(3);

自动拆箱

自动拆箱:跟自动装箱的方向相反,如将 Integer 这样的引用类型的对象重新简化为基本类型的数据

例如

int i = new Integer(2); ---> int i = Integer.intValue(2);

编译器内部会调用 intValue() 返回该 Integer 对象的 int

其它具有缓存机制的基本类型

不仅 intJava 中的另外 7 种基本类型都可以自动装箱和自动拆箱,其中也有用到缓存

  • ByteCache 用于缓存 Byte 对象,ShortCache 用于缓存 Short 对象,LongCache 用于缓存 Long 对象,CharacterCache 用于缓存 Character 对象
  • 这些类都有缓存的范围:Byte,Short,Integer,Long-128127Character 范围为 0127
  • 除了 Integer 可以通过 jvm 参数改变范围外,其它的都不行

Integer 的实例化方式

Integer 的构造方法

public Integer(int value) {this.value = value;
}public Integer(String s) throws NumberFormatException {this.value = parseInt(s, 10);
}

Integer 的实例化方式

Integer a = new Integer(100);// 第一种
Integer b = new Integer("200");// 第二种
Integer c = 300;// 第三种
Integer d = Integer.valueOf(400);// 第四种

经典案列

案列一

public class IntegerTest {public static void main(String[] args) {int a = 1;Integer b = Integer.valueOf(1);Integer c = new Integer(1);System.out.println(a == b);System.out.println(a == c);System.out.println(b == c);}
}结果:
true
true
false

案列分析

  • a 是基本类型,bc 是引用类型,两者进行比较时有一个自动拆箱的过程,也就是会默认调用 bcintValue() 方法;最终比较的是基本类型的值,自然是相等的
public int intValue() {return value;
}
  • bc 虽然都是引用类型;而 b 是从 IntegerCache 缓存中拿到的引用变量;而 c 是使用 new 在堆内存中创建出来的实例,故而是 false

案列二

public class IntegerTest {public static void main(String[] args) {Integer num1 = new Integer(100);Integer num2 = new Integer(100);System.out.println(num1 == num2);Integer num5 = 128;Integer num6 = 128;System.out.println(num5 == num6);Integer num7 = 100;Integer num8 = new Integer(100);System.out.println(num7 == num8);}
}结果:
false
false
false

案列分析

  • num1num2 的内存地址不一样,== 的比较如果是引用类型的话,那么比较的是引用的堆内存地址,new 产生的对象一定是新的内存地址,这里和 Integer 的缓存机制无关的,最终的结果便是 false
  • 128 已经不在 -128~127 之间了,无法使用 Integer 的缓存机制,所以会 new 新对象,那么就是 false
  • 因为 num8 是从堆内存中 new 出来的,而 num7 是从 IntegerCache 缓存中拿到的引用变量,所以使用的内存地址和 num7 不一致,结果为 false

Integer类的缓存机制相关推荐

  1. java字面量和符号引用_java中字面量,常量和变量之间的区别(附:Integer缓存机制)...

    一.引子 在各种教科书和博客中这三者经常被引用,今天复习到内存区域,想起常量池中就是存着字面量和符号引用,其实这三者并不是只在java中才有,各个语言中都有类似的定义,所以做一下总结,以示区分. 二. ...

  2. JAVA中Integer的缓存机制

    Integer的缓存机制: Integer是对小数据(-128~127)是有缓存的,再jvm初始化的时候,数据-128~127之间的数字便被缓存到了本地内存中,如果初始化-128~127之间的数字,会 ...

  3. MyBatis复习笔记6:MyBatis缓存机制

    MyBatis缓存机制 MyBatis 包含一个非常强大的查询缓存特性,它可以非常方便地配置和定制.缓存可以极大的提升查询效率. MyBatis系统中默认定义了两级缓存. 一级缓存和二级缓存. 默认情 ...

  4. java int类源码,一起学JDK源码 -- Integer类

    Integer类为java基本类型int的包装类,除了前面提到的Byte类,Short类中的大部分方法,Integer类中还提供了很多处理int类型的方法,接下来就让我们一起看看吧. 基础知识: 1. ...

  5. Hibernate 缓存机制

    转载:http://www.cnblogs.com/wean/archive/2012/05/16/2502724.html 一.why(为什么要用Hibernate缓存?) Hibernate是一个 ...

  6. android 视频的缩略图 缓存机制和 异步加载缩略图

    在这次的工作开发项目中,涉及到一个视频缩略图的视频列表:这个在大家看来,制作视频缩略图就是两行代码就搞定的事.确实是这样的,百度一下,每个帖子都知道制作视频缩略图的方法,在这里确实也是一样的,但是我要 ...

  7. 实现 LRU 缓存机制

    实现 LRU 缓存机制 文章目录 实现 LRU 缓存机制 一.什么是 LRU 算法 二.LRU 算法描述 三.LRU 算法设计 四.代码实现 一.什么是 LRU 算法 LRU 就是一种缓存淘汰策略.( ...

  8. (11) Hibernate 缓存机制

    一.why(为什么要用Hibernate缓存?) Hibernate是一个持久层框架,经常访问物理数据库. 为了降低应用程序对物理数据源访问的频次,从而提高应用程序的运行性能. 缓存内的数据是对物理数 ...

  9. Java中整型的缓存机制

    本文将介绍Java中Integer的缓存相关知识.这是在Java 5中引入的一个有助于节省内存.提高性能的功能.首先看一个使用Integer的示例代码,从中学习其缓存行为.接着我们将为什么这么实现以及 ...

  10. Hibernate中的三种数据持久状态和缓存机制

    Java三大框架之--Hibernate中的三种数据持久状态和缓存机制 Hibernate中的三种状态   瞬时状态:刚创建的对象还没有被Session持久化.缓存中不存在这个对象的数据并且数据库中没 ...

最新文章

  1. 15.4 xshell使用xftp传输文件;15.5 使用pure-ftpd搭建ftp服务
  2. 研究人工智能最应该注意的问题
  3. [蓝桥杯2015初赛]移动距离
  4. CodeForces 1361E James and the Chase(dfs + 结论)
  5. 【渝粤教育】 国家开放大学2020年春季 1192高层建筑施工 参考试题
  6. 硬盘计算机类比推理,判断推理类比推理:储存:光盘:硬盘 A:晾晒:绳索:衣架 B.吃...
  7. 肯耐珂萨助力世界500强零售企业在线春招:单次面试3000人
  8. HUABASE :基于列存储的关系型数据库系统
  9. html怎么在服务器环境,如何搭建node服务器环境?
  10. 去掉超链接或图片热点链接虚线框
  11. 2022微服务面试题 最新50道题(含答案解析)
  12. LabVIEW编程LabVIEW开发在LabVIEW中复用现有代码
  13. 知乎热议:35岁,你要逃离北上广?
  14. 关于在谷歌浏览器,vue-video-player 实现断点续播,currentTime不生效问题
  15. 1472_TC275的看门狗简介以及安全看门狗及CPU看门狗的区分
  16. 面试造火箭,秋招建大楼!阿里新出《Java权威面试指南》堪称精品!
  17. 苹果cms安装PHP,苹果cms图文安装教程和苹果cms模板安装教程详解
  18. 企业网络安全|监控解决方案
  19. android 多层json,Android json解析:根据嵌套key值逐层获取最底层数据
  20. HPB芯链正式发布其测试网络,软硬件结合突破性能瓶颈

热门文章

  1. 网络中的网络 NiN 动手学深度学习v2 pytorch
  2. 继承、关联、聚合、组合的代码表示
  3. 数据是指在计算机科学中能够被,5. 数据在 计算机科学中 是指所有能输入到计算机并 被计算机程序处理的符号的总称。( )...
  4. 字符串中拼接v-for_C#中几种拼接字符串的方法
  5. 图解tcpip 第5版 pdf_16G906国标图集,装配式混凝土剪力墙结构住宅施工图解,PDF版...
  6. 动态规划 分享巧克力 4794_包装|颇具艺术欣赏性的巧克力创意包装设计
  7. AR引擎vuforia源码分析、中文注释(1)
  8. 彻底解决git中.gitignore文件失效原因及解决办法
  9. java基础学习(4)
  10. 【Codeforces Round #516_div2_E】【二分交互题】Dwarves, Hats and Extrasensory Abilities