面试连环炮之Integer和int
最近在招聘面试的过程中,考察一些候选人的基础掌握能力中发现,还是有大多数干了有1~3年的开发者在基础这块儿掌握的不够牢靠,没有去思考过为什么这样做,以及这样做的原因是什么?那么今天我们就来聊聊Java中的Integer和int,以及他们在面试中一般会如何考候选人呢?
想查看更多的文章请关注公众号:IT巡游屋
首先我们来看如下的一些面试连环炮:
- 开发中你在定义常量的时候,一般是用的Integer还是int,他们之间有什么区别?
- 什么叫包装类,它是如何包装基本类型的?
- Integer的自动装箱和自动拆箱的原理是什么?以及所发生在哪个阶段?带来的好处和坏处是什么?什么情况下会发生自动装箱/自动拆箱?
- 那你能说下Integer的值缓存是什么吗?
- 你觉得 Integer的源码有哪些设计要点?
或者还有诸如以下的一些笔试题:
public static void main(String[] args) {Integer a = 100;Integer b = 100;System.out.println(a == b);Integer c = 200;Integer d = 200;System.out.println(c == d);}
请问:ab的值以及cd的值分别是多少?
以上问题大家可以先思考下如果面试中遇到你会如何回答?
首先来条华丽的分割线
一. Java包装类、装箱和拆箱
1.1 包装类
在 Java的设计中提倡一种思想,即一切皆对象。但是从数据类型的划分中,我们知道 Java 中的数据类型分为基本数据类型和引用数据类型,但是基本数据类型怎么能够称为对象呢?于是 Java 为每种基本数据类型分别设计了对应的类,称之为包装类(Wrapper Classes),也有地方称为外覆类或数据类型类。
我们来看下基本类型对应的包装类:
基本数据类型 | 包装类 |
---|---|
byte | Byte |
short | hort |
int | Integer |
long | Long |
boolean | Boolean |
char | Character |
folat | Float |
double | Double |
两个维度分析:
- 从内存占用角度:包装类是对象,除了基本数据以外,还需要有对象头。所以包装类占的空间比基本类型大。
- 从处理速度角度:基本类型在内存中存的是值,找到基本类型的内存位置就可以获得值;而包装类型存的是对象的引用,找到指定的包装类型后,还要根据引用找到具体对象的内存位置。会产生更多的IO,计算性能比基本类型差。
因此在开发中,如果需要做计算,尽量优先使用基本类型。
那么大家思考一个问题:Java为什么还要设计出包装类来使用?目的是什么?
1.2 为什么使用包装类
在Java开发中,特别是在企业中开发的时候处理业务逻辑的过程中,我们通常都要使用Object类型来进行数据的包装和存储,Object更具备通用的能力,更抽象,解决业务问题编程效率高。而基本类型的包装类,相当于将基本类型“包装起来”,使得它具有了对象的性质,并且为其添加了属性和方法,丰富了基本类型的操作。特别是:Java的泛型,我们的基本数据类型并不能和泛型配合使用,因此要想配合泛型使用也得保证类型可以转换为Object。
同样的我们今天要说的Integer就是int的包装类,除了提供int类型的字段进行存储外,还给我们提供了基本操作,比如数学运算、int和字符串之间的转换等,我们可以来看看:
可以看到我们Integer中的方法前面都有M,代表大部分方法是静态方法,可以直接使用,并且里面还有很多的变量都是使用了final进行修饰:
变量里面的value即是用来存储我们的int值的,也就是被Integer包装的值,被private final修饰后,是无法被访问的且经过构造函数赋值后无法被改变:(其余的成员变量都是被static所修饰)
/*** The value of the {@code Integer}.** @serial*/private final int value;/*** Constructs a newly allocated {@code Integer} object that* represents the specified {@code int} value.** @param value the value to be represented by the* {@code Integer} object.*/public Integer(int value) {this.value = value;}
引用网上一位博主的解释:
JAVA设计者的初衷估计是这样的:如果开发者要做计算,就应该使用primitive value如果开发者要处理业务问题,就应该使用object,采用Generic机制;反正JAVA有auto-boxing/unboxing机制,对开发者来讲也不需要注意什么。然后为了弥补object计算能力的不足,还设计了static valueOf()方法提供缓存机制,算是一个弥补。
这里提到了auto-boxing/unboxing机制,没错这就是接下来我们要讲的 自动装箱/自动拆箱 机制
1.3 自动装箱
平时我们写代码的过程中,比如定义一个变量i为10,我们一般会写:int i = 10;
那么我们也可以使用包装类:Integer i = 10;
或Integer i = new Integer(10)
可以达到相同的效果;
这里Integer i = 10;
即使用了「自动装箱」的机制,在Integer的内部实际是使用:Integer i = Integer.valueOf(10);
所以我们要来看看 valueOf这个方法到底是如何实现的:
/*** 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);}
可以从文档注释中也能发现,该方法是JDK1.5引入的一个方法,并且返回的是一个Integer的实例,也就是通过该方法也能直接得到一个Integer对象,并且注释文档也说明了:如果不需要新的实例,通常应该优先使用此方法,而不是直接走构造函数,因此此方法可能通过频繁缓存产生明显更好的空间和时间性能,和要求的价值。This method will always cache values in the range -128 to 127, inclusive, and may cache other values outside of this range. 此方法将始终缓存-128到127(包括端点)范围内的值,并可以缓存此范围之外的其他值
1.4 缓存设计
valueOf 方法中 IntegerCache.low = -128; IntegerCache.high = 127 ; 也就是当我们传入的int 值在-128~127之间这个范围时, 会返回:return IntegerCache.cache[i + (-IntegerCache.low)];
接下来我们一起看看 IntegerCache这个类是如何定义的:(注意看注释)
private static class IntegerCache {static final int low = -128;static final int high;//初始化的时候没有直接赋值static final Integer cache[];static {// high value may be configured by propertyint h = 127;//附默认值为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_VALUEh = Math.min(i, Integer.MAX_VALUE - (-low) -1);} catch( NumberFormatException nfe) {// If the property cannot be parsed into an int, ignore it.}}high = h;//配置文件中有值,并且满足上方条件对比及可更改high值cache = new Integer[(high - low) + 1];//初始化cache数组,并且长度为127+128+1=256int j = low;//j=-128for(int k = 0; k < cache.length; k++)cache[k] = new Integer(j++);//创建-128~127对应的Integer对象,缓存在数组中//0的位置对应 -128 ----> 128的位置对应的值就是0//1的位置对应 -127//......//10的位置对应 -118 -----> 138的位置对应的值就是10// range [-128, 127] must be interned (JLS7 5.1.7)assert IntegerCache.high >= 127;}private IntegerCache() {}}
上方for循环里大家看注释应该就能推演出公式:我们传入的i值如果符合-128~127范围,要想取出对应的缓存值那么应该在cache数组的 i + (-low)即:i+128,从索引为138的位置取出对应的值,就是10
为什么设计这个缓存?
实践发现,大部分数据操作都是集中在有限的、较小的数值范围。所以在Java 5 中增加了静态工厂方法 valueOf(),在调用它的时候利用缓存机制,这样不用反复new 值相同的Integer对象,减少了内存占用。
1.5 自动拆箱
什么情况下Integer会自动拆箱呢,比如下面的代码:
Integer i = new Integer(10);
int j = 20;
System.out.print(i == j);
由于i是integer类型,j是基本类型,当两者需要进行比较的时候,i 就需要进行自动拆箱为int,然后进行比较;其中自动拆箱使用的是 intValue() 方法 。
看看源码,直接返回value值即可:
/*** Returns the value of this {@code Integer} as an* {@code int}.*/public int intValue() {return value;}
从注释中可以发现其实该方法是来自Number类,而我们的Integer是继承至Number类,同时还实现了Comparable接口
public final class Integer extends Number implements Comparable<Integer> {
Number 是一个抽象类,主要表示基本类型之间的转换。
好了,到这儿就基本上把Integer相关的核心源码看完了,同时也能清晰的知道包装类,以及自动装箱和自动拆箱的使用以及原理。
二. 常见面试题
2.1 Integer和int的区别:
1、Integer是int的包装类,int则是java的一种基本数据类型
2、Integer变量必须实例化后才能使用,而int变量不需要
3、Integer实际是对象的引用,当new一个Integer时,实际上是生成一个指针指向此对象;而int则是直接存储数据值
4、Integer的默认值是null,int的默认值是0
2.2 常见问答:
问1:
public static void main(String[] args) {Integer a = 100;Integer b = 100;System.out.println(a == b);Integer c = 200;Integer d = 200;System.out.println(c == d);}
现在我们再来看文章开头的时候这个问题,大家能说出答案了吗?
答案: ab 为true; cd为false
原因分析:
Integer a = 100; 实际上会被翻译为: Integer a = ValueOf(100); 从缓存中取出值为100的Integer对象;同时第二行代码:Integer b = 100; 也是从常量池中取出相同的缓存对象,因此a跟b是相等的
而c 和 d 因为赋的值为200,已经超过 IntegerCache.high 会直接创建新的Integer对象,因此两个对象相比较肯定不相等,两者在内存中的地址不同。
问2:
Integer a = 100;
int b = 100;
System.out.println(a == b);
Integer a = new Integer(100);
int b = 100;
System.out.println(a == b);
答案为:ture,因为a会进行自动拆箱取出对应的int值进行比较,因此相等
问3:
Integer a = new Integer(100);
Integer b = new Integer(100);
System.out.println(a == b);
答案为:false,因为两个对象相比较,比较的是内存地址,因此肯定不相等
问4:
最后再来一道发散性问题,大家可以思考下输出的结果为多少:
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {Class cache = Integer.class.getDeclaredClasses()[0];Field myCache = cache.getDeclaredField("cache");myCache.setAccessible(true);Integer[] newCache = (Integer[]) myCache.get(cache);newCache[132] = newCache[133];int a = 2;int b = a + a;System.out.printf("%d + %d = %d", a, a, b); }
答案为: 2 + 2 = 5. 大家可以下来自己好好思考下为什么会得到这个答案
面试连环炮之Integer和int相关推荐
- Integer vs int
http://www.cnblogs.com/liuling/archive/2013/05/05/intAndInteger.html 如果面试官问Integer与int的区别:估计大多数人只会说道 ...
- Integer与int的种种比较你知道多少?[转]
2019独角兽企业重金招聘Python工程师标准>>> 转载:http://www.cnblogs.com/liuling/archive/2013/05/05/intAndInte ...
- java中 int 比较_java中Integer与int的种种比较你知道多少?
如果面试官问Integer与int的区别:估计大多数人只会说道两点,Ingeter是int的包装类,int的初值为0,Ingeter的初值为null.但是如果面试官再问一下Integer i = 1; ...
- Integer与int的比较与区别
如果面试官问Integer与int的区别:估计大多数人只会说道两点,Ingeter是int的包装类,int的初值为0,Ingeter的初值为null.但是如果面试官再问一下Integer i = 1; ...
- Integer与int的区别
如果面试官问Integer与int的区别:估计大多数人只会说道两点,Ingeter是int的包装类,int的初值为0,Ingeter的初值为null.但是如果面试官再问一下Integer i = 1; ...
- 你知道Integer和int的区别吗
最近小康面试,突然被面试官问道,说一下Integer和int的区别.额-可能平时就知道写一些业务代码以及看一些自己觉得比较高大上的东西,包括面试也看的一些Spring源码等,对于这种java特别基础的 ...
- 教拉克丝去面试(一),String转换成int的几种方式
这是一篇用趣味化的形式给大家来讲java面试, "语不惊人死不休",没错,本篇文章的标题就是这么酷炫,接受不了的同学就别点进来看了,所谓好奇心害死猫:能够接受的同学我只能说你赚到了 ...
- integer比较_傻傻分不清?Integer、new Integer() 和 int 的面试题
基本概念的区分 1.Integer 是 int 的包装类,int 则是 java 的一种基本数据类型 2.Integer 变量必须实例化后才能使用,而int变量不需要 3.Integer 实际是对象的 ...
- java integer int 比较_java Integer和int之间的比较问题是什么?
展开全部 java Integer和int之间e68a84e8a2ad3231313335323631343130323136353331333365633864==的比较问题.求解释 public ...
最新文章
- 修改Xmodem/Zmodem上传下载路径
- 【洛谷P1378】油滴扩展
- 韦东奕:被数学“选中”的天才
- [扮演不同的角色 知道不同的成就]2008.06.20 黄桃西米露
- 实现DropDownList 无刷新的联动效果
- Zephry I2C和SPI驱动器介绍和操作FM24V10闪存
- java day08【String类、static关键字、Arrays类、 Math类】
- CPU占用率高的可能性与解决办法
- iconfont阿里巴巴矢量图标库使用步骤
- 365家装智选联盟:为什么说不要在冬天装修?
- Android 仿微信小程序开屏页加载loading
- Java解P2678 [NOIP2015 提高组] 跳石头,有图有注释,通俗易懂
- vs2017.NET智能提示的英文改为中文
- /oa/web应用程序中的服务器错误修复,如何处理OA系统在线阅读或编辑文档时weboffice控件提示“文件存取错误”的问题?...
- 面试算法———回溯经典题目
- 【控制理论】滑模控制最强解析
- 把别人漂亮的QQ空间克隆一份
- 【webrtc】fdk-aac 编解码库cmake和 gn编译
- FFMpeg视频开发与应用基础——使用FFMpeg工具与SDK-殷汶杰-专题视频课程
- 关于AD转换设计中的基本问题
热门文章
- 十个技巧,为论文创建吸引人的标题
- 001html5新增常用标签
- NB-IoT低功耗芯片:国产新秀移芯EC616,能挑战联发科MT2625吗?来看看使用低功耗分析仪做的对比功耗评测,评测对象:采用移远BC26和BC260Y模块开发板。
- TOTOLINK NR1800X 系列 CVE 分析
- CorelDRAW插件-GMS开发-绘制几何图形-路径和组合路径
- 微信打开链接提示“该网页包含不安全内容,已停止访问”的解决方案
- Android开源益智游戏“斗地主”单机版源代码
- 一文了解 MySQL 中的锁
- QT选择颜色的调色板功能
- Hashmap 原理、源码、面试题(史上最全)