Java自动装箱缓存机制

尝试运行这段代码:

相似的两段代码,得到的结果却完全不相同。

首先要知道在java中==比较的是对象的引用,从直觉出发,无论是integer1、integer2还是integer3、integer4都是不同的引用,结果都应该是不等的。

造成这个结果的原因是JDK1.5引入的包装类自动装箱时的缓存机制

自动装箱的概念:

Integer a = 10; //自动装箱,相当于下面这句
Integer a = Integer.valueOf(10);

而看看Integer中valueOf(int)的源码:

public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];//这句就是我们要研究的重点
    return new Integer(i);
}

IntegerCache是一个缓存类,它的内部有一个静态的Integer cache[]数组,在这个类第一次被加载时,会用整数值在-128~127之间的Integer实例对象填充这个数组,如果调用valueOf方法的时候参数值在这个范围内,就会从IntegerCache中的cache数组去取出这样一个共享对象。

这样就能回答一开始的程序integer1、integer2为什么相等了,因为他们都是从cache数组中取出来的同一个引用。

而300这个数是不在-128~127之间的,缓存数组中不存在这样的对象,最终是调用了构造方法创建了两个不同的Integer对象。


拓展:IntegerCache的静态代码块

static {
    // 缓存的数据范围可以由用户设置,这里从配置中获取了用户设置的缓存范围
    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;

    // 这里循环构造Integer对象填充cache数组
    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;
}

原创文章,作者:彭晨涛,如若转载,请注明出处:https://www.codetool.top/article/java%e8%87%aa%e5%8a%a8%e8%a3%85%e7%ae%b1%e7%bc%93%e5%ad%98%e6%9c%ba%e5%88%b6/

(0)
彭晨涛彭晨涛管理者
上一篇 2019年12月4日 18:05
下一篇 2019年12月6日

相关推荐

  • 按键排序的Map-TreeMap源码分析

    总结 总结放前面(这篇挺短的)1. TreeMap基于红黑树实现,可以对Map中的key排序2. 它的排序和定位需要依赖比较器或实现 Comparable 接口,也因此不需要key…

    Java 2020年2月16日
    0130
  • 详解Java中的四种引用及其应用

    本文参考资源: 深入理解Java中的引用(一)——Reference - 简书 深入理解Java中的引用(二)——强软弱虚引用 - 简书 深入理解Java中的引用(三)——Dire…

    2020年2月14日
    0190
  • AbstractCollection默认集合类

    AbstractCollection用于实现基本的Collection结构,提供给普通用户继承使用。也是JDK集合类的父类,部分方法是没有被重载的。 相比Collection接口并…

    Java 2019年11月18日
    0100
  • JDK8-Stream流库详解

    流提供了一种让我们可以在比集合更高的概念级别上指定计算的数据视图。通过使用流,我们可以说明想要完成什么任务,而不是说明如何去实现它。 流的创建 Collection.stream(…

    Java 2020年2月11日
    0150
  • 深入理解java虚拟机第三版读书笔记11

    以下是第十一章 后端编译与优化的内容 把Class文件转换成与本地基础设施(硬件指令集、操作系统)相关的二进制机器码可以视为整个编译过程的后端。 最近几年提前编译也开始兴起,我们在…

    2020年1月27日
    0290
  • 深入理解java虚拟机第三版读书笔记06

    附: Java虚拟机规范-Class文件格式:JDK8 Java虚拟机规范-Class文件格式:JDK13 以下是第六章 类文件结构的内容 Class类文件的结构 Class文件是…

    Java 2020年1月18日
    0180
  • 深入理解java虚拟机第三版读书笔记12

    以下是第十二章 Java内存模型与线程的内容 硬件的效率与一致性 基于高速缓存的存储交互很好地解决了处理器与内存速度之间的矛盾,但是也为计算机系统带来更高的复杂度,它引入了一个新的…

    2020年1月29日
    01540
  • JUC包下的信号量Semaphore

    概述 信号量,用来限制能同时访问共享资源的线程上限。 public static void main(String[] args) { // 1. 创建 semaphore 对象 …

    Java 2020年2月6日
    0200
  • CountDownLatch及CyclicBarrier源码分析

    之前写的一篇博客JUC包下的线程协作计数CountDownLatch及CyclicBarrier只是介绍了一下这两个工具类的用法,并没有深入探究源码,然而实现方法也比较简单,所以合…

    Java 2020年5月22日
    0140
  • 深入理解java虚拟机第三版读书笔记02

    以下是第二章 Java内存区域与内存溢出异常的内容 运行时数据区域 程序计数器 特点 程序计数器是一块较小的内存空间,它可以看作是当前线程所执行的字节码的行号指示器。 程序计数器是…

    2020年1月5日
    0200

发表回复

登录后才能评论