Java自动装箱中的缓存原理
今天看到一道'经典'面试题:
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自动装箱中的缓存原理的更多相关文章
- java 自动装箱自动拆箱
1.Java数据类型 在介绍Java的自动装箱和拆箱之前,我们先来了解一下Java的基本数据类型. 在Java中,数据类型可以分为两大种,Primitive Type(基本类型)和Reference ...
- Java 自动装箱与拆箱
Java 自动装箱与拆箱(Autoboxing and unboxing) 什么是自动装箱拆箱 基本数据类型的自动装箱(autoboxing).拆箱(unboxing)是自J2SE 5.0开始提供 ...
- Java自动装箱和自动拆箱操作
1.Java数据类型 在介绍Java的自动装箱和拆箱之前,我们先来了解一下Java的基本数据类型. 在Java中,数据类型可以分为两大种,Primitive Type(基本类型)和Reference ...
- java自动装箱拆箱总结
对于java1.5引入的自动装箱拆箱,之前只是知道一点点,最近在看一篇博客时发现自己对自动装箱拆箱这个特性了解的太少了,所以今天研究了下这个特性.以下是结合测试代码进行的总结. 测试代码: int a ...
- JAVA自动装箱拆箱与常量池
java 自动装箱与拆箱 这个是jdk1.5以后才引入的新的内容,作为秉承发表是最好的记忆,毅然决定还是用一篇博客来代替我的记忆: java语言规范中说道:在许多情况下包装与解包装是由编译器自行完成的 ...
- 【转】java 自动装箱与拆箱
java 自动装箱与拆箱 这个是jdk1.5以后才引入的新的内容,作为秉承发表是最好的记忆,毅然决定还是用一篇博客来代替我的记忆: java语言规范中说道:在许多情况下包装与解包装是由编译器自行完成的 ...
- Java进阶(三十七)java 自动装箱与拆箱
Java进阶(三十七)java 自动装箱与拆箱 前言 这个是jdk1.5以后才引入的新的内容.java语言规范中说道:在许多情况下包装与解包装是由编译器自行完成的(在这种情况下包装称为装箱,解包装称为 ...
- JAVA基础之——三大特征、接口和抽象类区别、重载和重写区别、==和equals区别、JAVA自动装箱和拆箱
1 java三大特征 1)封装:即class,把一类实体定义成类,该类有变量和方法. 2)继承:从已有的父类中派生出子类,子类实现父类的抽象方法. 3)多态:通过父类对象可以引用不同的子类,从而实现不 ...
- JAVA和C#中数据库连接池原理与应用
JAVA和C#中数据库连接池原理 在现在的互联网发展中,高并发成为了主流,而最关键的部分就是对数据库操作和访问,在现在的互联网发展中,ORM框架曾出不穷, 比如:.Net-Core的EFCore.Sq ...
随机推荐
- 一:requests爬虫基础
一,什么是爬虫? 描述: 本质是一个自动化程序,一个模拟浏览器向某一个服务器发送请求获取响应资源的过程. 爬虫的基本流程 robots.txt协议 编写一个robots.txt的协议文件来约束爬虫程序 ...
- synchronized中判断条件用while而不是if
假设一个生产者生产一个产品,两个消费者A,B去取这个商品. 使用if: A去取商品,发现空,于是等待... B去取商品,发现空,于是等待... 生产者生产商品,唤醒他们 B先争到锁,从wait()后执 ...
- 串口.Qt532测试(异步)
环境:Win7x64.Qt5.3.2 MSVC OpenGL(x86).vs2010(x86) 项目所在位置:E:\Project_Qt532\SeriesPort_Qt532_Z ZC:这里 同步方 ...
- ABP的配置 请求类型
1.ServerRootAddress 项目运行的根地址 需要跟启动项目配置的地址相同 2.CorsOrigins 允许哪些地址访问 不会出现跨域 启动项目配置的地址
- openstack环境搭建常用命令
1,编辑/etc/selinux/config文件,关闭selinux SELINUX=disabled 2,清空iptables规则并保存 # iptables -F # service iptab ...
- nodejs实现文件的拷贝复制
var fs = require( 'fs' ), stat = fs.stat; /* 05 * 复制目录中的所有文件包括子目录 06 * @param{ String } 需要复制的目录 07 * ...
- 第 8 章 容器网络 - 061 - flannel 的连通与隔离
flannel 的连通与隔离 测试 bbox1 和 bbxo2 的连通性: bbox1 能够 ping 到位于不同 subnet 的 bbox2,通过 traceroute 分析一下 bbox1 到 ...
- JS 日期比较方法
1.日期参数格式:yyyy-mm-dd // a: 日期a, b: 日期b, flag: 返回的结果 function duibi(a, b,flag) { var arr = a.split(&qu ...
- Redhat 5.7 安装 glibc debuginfo ,终于成功。
1) yum --enablerepo rhel-debuginfo install glibc-debuginfo 安装完之后,yum list 可以看出debuginfo 是 build 123, ...
- reactiveCocoa使用
@代理 简介:使用RACSubject信号替换 控制器2的操作: <1在头文件定义一个信号: @property (nonatomic, strong) RACSubject *delegate ...