Hold住面试官之Integer Cache
前言
最近跟许多朋友聊了下,在这个“跳槽”的黄金季节,大家都有点蠢蠢欲动,所以最近就多聊聊面试的时候需要注意的一些问题,这些问题不一定多深奥,多复杂,但是一不注意的话却容易掉坑。下面看一下面试的时候经常遇到的一段代码:
public class IntegerDemo { public static void main(String[] args) { Integer numA = 127; Integer numB = 127; Integer numC = 128; Integer numD = 128; System.out.println("numA == numB : "+ (numA == numB)); System.out.println("numC == numD : "+ (numC == numD)); } }
根据大家以往的经验,会认为上面的代码用“==“符号来比较,对比的是对象的引用,那么ABCD是不同的对象,所以输出当然是false了。我在《“==”、“equals()”、“hashcode()”之间的秘密》这篇文章也讨论过。那么事实也是如此吗?下面看一下输出结果:
numA == numB : true numC == numD : false
What?这个输出结果怎么跟以往的认知有所出入呢?在我们的代码“Integer numA = 127”中,编译器会把基本数据的“自动装箱”(autoboxing)成包装类,所以这行代码就等价于“Integer numA = Integer.valueOf(127)”了,这样我们就可以进入valueOf方法查看它的实现原理。
//Integer valueOf方法 public static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); } //Integer静态内部类 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() {} }
从上面的源码可以看到,valueOf方法会先判断传进来的参数是否在IntegerCache的low与high之间,如果是的话就返回cache数组里面的缓存值,不是的话就new Integer(i)返回。
那我们再往上看一下IntegerCache,它是Integer的内部静态类,low默认是-128,high的值默认127,但是high可以通过JVM启动参数XX:AutoBoxCacheMax=size来修改(如图),如果我们按照这样修改了,然后再次执行上面代码,这时候2次输出都是true,因为缓存的区间变成-128~200了。
但是如果我们是通过构造器来生成一个Integer对象的话,下面的输出都是false。因为这样不会走ValueOf方法,所以按照正常的对象对比逻辑即可。
public class IntegerDemo { public static void main(String[] args) { Integer numA = new Integer(127); Integer numB = new Integer(127); Integer numC = new Integer(128); Integer numD = new Integer(128); System.out.println("numA == numB : "+ (numA == numB));//false System.out.println("numC == numD : "+ (numC == numD));//false } }
还有需要注意的一点是,此类缓存行为不仅存在于Integer对象。还存在于其他的整数类型Byte,Short,Long,Character。但是能改变缓存范围的就只有Integer了。
结语
有时候往往越简单的知识越容易掉坑里,所以要保持自己的求知欲,不断巩固的基础,才能让自己在面试的时候不会栽跟头。
喜欢的话~关注一下微信公众号《深夜里的程序猿》,每天分享最干的干货
文章推荐
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
Hyperledger Fabric和VSCode的IBM区块链扩展开发智能合约
了解使用IBM Blockchain Platform的VSCode扩展来简化开发,测试和部署智能合约的过程。完成本教程后,你将了解如何使用VSCode在本地Hyperledger Fabric网络上快速开发,演示和部署区块链应用程序。本教程假设你对Hyperledger Fabric有一些基本的了解。 学习目标 安装IBM Blockchain Platform VSCode扩展。 创建一个新的JavaScript智能合约。 打包智能合约。 创建,探索和了解Hyperledger Fabric网络。 在本地Hyperledger Fabric实例上部署智能合约。 使用Node.js SDK与已部署的智能合约包进行交互。 先决条件 你需要安装以下内容才能使用扩展程序: node v8.x或更高版本以及npm v5.x或更高版本。 Yeoman(yo) v2.x。 Docker版本v17.06.2-ce或更高版本。 Docker Compose v1.14.0或更高版本。 VSCode 1.28.2或更高版本。 如果你使用的是Windows,则还必须确保以下内容: 你的Windows版本...
- 下一篇
打通前后端逻辑,客户端Flutter代码一天上线
一、前沿 随着闲鱼的业务快速增长,运营类的需求也越来越多,其中不乏有很多界面修改或运营坑位的需求。闲鱼的版本现在是每2周一个版本,如何快速迭代产品,跳过窗口期来满足这些需求?另外,闲鱼客户端的包体也变的很大,企业包的大小,iOS已经到了94.3M,Android也到了53.5M。Android的包体大小,相比2016年,已经增长了近1倍,怎么能将包体大小降下来?首先想到的是如何动态化的解决此类问题。 对于原生的能力的动态化,Android平台各公司都有很完善的动态化方案,甚至Google还提供了Android App Bundles让开发者们更好地支持动态化。由于Apple官方担忧动态化的风险,因此并不太支持动态化。因此动态化能力就会考虑跟Web结合,从一开始基于 WebView 的 Hybrid 方案 PhoneGap、Titanium,到现在与原生相结合的 React Native 、Weex。 但Native和JavaScript Context之间的通讯,频繁的交互就成了程序的性能瓶颈。于此同时随着闲鱼Flutter技术的推广,已经有10多个页面用Flutter实现...
相关文章
文章评论
共有0条评论来说两句吧...