今天看到一道'经典'面试题:

        Integer a = 100;
Integer b = 100;
System.out.println(a==b);
Integer a2 = 200;
Integer b2 = 200;
System.out.println(a2==b2);

答案运行一下就能很容易的得出:true,false.

这个题很'经典',之前也看过讲解,大体上说由于jdk的优化,存在一个缓存机制导致,但是一直没有自己去看过源码,今天正好又遇到了,就仔细的看了一下源码.

以Integer为例,JDK中的关键代码:

 /**
* Cache to support the object identity semantics of autoboxing for values between
* -128 and 127 (inclusive) as required by JLS.
*
* The cache is initialized on first usage. The size of the cache
* may be controlled by the {@code -XX:AutoBoxCacheMax=<size>} option.
* 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.
*/ 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() {}
}

从方法上的注释可以知道,JLS(Java语言规范)中定义了当处于-127-127之间的值时需要采用缓存机制,Oracle官网的原文如下:

If the value p being boxed is true, false, a byte, or a char in the range \u0000 to \u007f, or an int or short number between -128 and 127 (inclusive), 
then let r1 and r2 be the results of any two boxing conversions of p. It is always the case that r1 == r2.

原文链接: https://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.1.7

当第一次调用这个缓存类的时候会初始化这个缓存, 从代码中很清楚的看到其实它就是直接初始化了一个数组,然后一口气将上下限之间对应的包装类都创建出来.且这个上限值

还可通过JVM参数XX:AutoBoxCacheMax=<size>来设置.可以想象出有了这个缓存类后,每次调用的时候只要在这个区间内的都可以不用再创建包装类,直接从缓存中取出来即可,

这个用法有点像String的常量池.装箱的源码如下:

    /**
* Returns an {@code Integer} instance representing the specified
* {@code int} value. If a new {@code Integer} instance is not
* required, this method should generally be used in preference to
* the constructor {@link #Integer(int)}, as this method is likely
* to yield significantly better space and time performance by
* caching frequently requested values.
*
* This method will always cache values in the range -128 to 127,
* inclusive, and may cache other values outside of this range.
*
* @param i an {@code int} value.
* @return an {@code Integer} instance representing {@code i}.
* @since 1.5
*/
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}

再回过头来看一下那道面试题也就很清楚原因了,一个是使用到了这个缓存,另一个由于超出默认范围,所以直接调用的构造方法创建的新对象.

明白了这个缓存机制后,其实很多的时候我们担心的性能问题就根本不存在了,因为大多数情况下这个装箱都是走的缓存.但同时也要注意,当我们错误的使用==来判断2个包装类的

值是否相等时,由于这个缓存机制的存在,可能导致错误极难被发现,或是随机产生错误判断.

Java自动装箱中的缓存原理的更多相关文章

  1. java 自动装箱自动拆箱

    1.Java数据类型 在介绍Java的自动装箱和拆箱之前,我们先来了解一下Java的基本数据类型. 在Java中,数据类型可以分为两大种,Primitive Type(基本类型)和Reference ...

  2. Java 自动装箱与拆箱

    Java 自动装箱与拆箱(Autoboxing and unboxing)   什么是自动装箱拆箱 基本数据类型的自动装箱(autoboxing).拆箱(unboxing)是自J2SE 5.0开始提供 ...

  3. Java自动装箱和自动拆箱操作

    1.Java数据类型 在介绍Java的自动装箱和拆箱之前,我们先来了解一下Java的基本数据类型. 在Java中,数据类型可以分为两大种,Primitive Type(基本类型)和Reference ...

  4. java自动装箱拆箱总结

    对于java1.5引入的自动装箱拆箱,之前只是知道一点点,最近在看一篇博客时发现自己对自动装箱拆箱这个特性了解的太少了,所以今天研究了下这个特性.以下是结合测试代码进行的总结. 测试代码: int a ...

  5. JAVA自动装箱拆箱与常量池

    java 自动装箱与拆箱 这个是jdk1.5以后才引入的新的内容,作为秉承发表是最好的记忆,毅然决定还是用一篇博客来代替我的记忆: java语言规范中说道:在许多情况下包装与解包装是由编译器自行完成的 ...

  6. 【转】java 自动装箱与拆箱

    java 自动装箱与拆箱 这个是jdk1.5以后才引入的新的内容,作为秉承发表是最好的记忆,毅然决定还是用一篇博客来代替我的记忆: java语言规范中说道:在许多情况下包装与解包装是由编译器自行完成的 ...

  7. Java进阶(三十七)java 自动装箱与拆箱

    Java进阶(三十七)java 自动装箱与拆箱 前言 这个是jdk1.5以后才引入的新的内容.java语言规范中说道:在许多情况下包装与解包装是由编译器自行完成的(在这种情况下包装称为装箱,解包装称为 ...

  8. JAVA基础之——三大特征、接口和抽象类区别、重载和重写区别、==和equals区别、JAVA自动装箱和拆箱

    1 java三大特征 1)封装:即class,把一类实体定义成类,该类有变量和方法. 2)继承:从已有的父类中派生出子类,子类实现父类的抽象方法. 3)多态:通过父类对象可以引用不同的子类,从而实现不 ...

  9. JAVA和C#中数据库连接池原理与应用

    JAVA和C#中数据库连接池原理 在现在的互联网发展中,高并发成为了主流,而最关键的部分就是对数据库操作和访问,在现在的互联网发展中,ORM框架曾出不穷, 比如:.Net-Core的EFCore.Sq ...

随机推荐

  1. linux df

    显示磁盘使用情况 [hadoopuser@CNSZ443239 ~]$ df   文件系统                            1K-块           已用      可用 已 ...

  2. Java 中常见的各种排序算法汇总

    首先,Java中自已是有排序的 说明:(1)Arrays类中的sort()使用的是“经过调优的快速排序法”;(2)比如int[],double[],char[]等基数据类型的数组,Arrays类之只是 ...

  3. ASP.net MVC模式介绍(一)

    一.ASP.NET 支持三种不同的开发模式:Web Pages(Web 页面).MVC(Model View Controller 模型-视图-控制器)表现层.Web Forms(Web 窗体) mv ...

  4. [原][osg][oe]分析一块倾斜摄影瓦片的数据

    RangeMode PIXEL_SIZE_ON_SCREEN 首先我们看看原始数据的构成: 第12层:(第一层) 第23层:(最后一层) pagelod下面有N多的pagelod一层包裹一层 通过os ...

  5. SpringBoot:Maven创建一个HelloWorld

    先看一下百度百科的解释: Maven项目对象模型(POM:project object model),可以通过一小段描述信息来管理项目的构建,报告和文档的项目管理工具软件. Maven的核心功能便是合 ...

  6. 力扣(LeetCode)965. 单值二叉树

    如果二叉树每个节点都具有相同的值,那么该二叉树就是单值二叉树. 只有给定的树是单值二叉树时,才返回 true:否则返回 false. 思路 递归 java版 /** * Definition for ...

  7. Linux Ubuntu下用Android NDK 生成独立交叉编译链

    本文主要介绍使用Android NDK生成独立交叉编译链,然后使用独立交叉编译链编译Android程序 下载NDK 下载与自己操作系统相吻合的版本 下载地址 解压到安装目录(如~/myndk): ta ...

  8. 目前用到的一些os.path方法

    这里主要记录下os.path.join()的用法 目录结构如下 在readconfig.py中进行试验,如下 1.使用os.path.realpath(__file__)获取文件所在目录 import ...

  9. Oracle DB , 计算各个用户/schema 的磁盘占用空间

    http://www.dba-oracle.com/t_find_size_schema.htm Question:  How do I find the size of a schema in my ...

  10. Getting started with Processing 第六章总结

    平移,旋转和缩放 前言 在这一章节中,平移.旋转和缩放都是以原点为基准的.并且是通过控制坐标系原点的位置来达到图元平移,旋转.缩放的视觉效果.作者在文中的原话是:另一种在屏幕上改变位置和移动物体的技术 ...