首页 > 编程语言 >java面试技巧:Integer和int的那些事⼉

java面试技巧:Integer和int的那些事⼉

时间:2023-01-28 21:32:40浏览次数:42  
标签:java int cache value 127 Integer 100


最近在招聘⾯试的过程中,考察⼀些候选⼈的基础掌握能⼒中发现,还是有⼤多数⼲了有1~3年的开发者在基础这块⼉掌握的不够牢靠,没有去思考过为什么这样做,以及这样做的原因是什么?那么今天我们就来聊聊Java中的Integer和int,以及他们在⾯试中⼀般会如何考候选⼈呢?

⾸先我们来看如下的⼀些⾯试连环炮:

  1. 开发中你在定义常量的时候,⼀般是⽤的Integer还是int,他们之间有什么区别?
  2. 什么叫包装类,它是如何包装基本类型的?
  3. Integer的⾃动装箱和⾃动拆箱的原理是什么?以及所发⽣在哪个阶段?带来的好处和坏处是什么? 什么情况下会发⽣⾃动装箱/⾃动拆箱?
  4. 那你能说下Integer的值缓存是什么吗?
  5. 你觉得 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);

}

请问:a==b的值以及c==d的值分别是多少?

以上问题⼤家可以先思考下如果⾯试中遇到你会如何回答?

⼀. Java包装类、装箱和拆箱

包装类

在 Java的设计中提倡⼀种思想,即⼀切皆对象。但是从数据类型的划分中,我们知道 Java 中的数据类型分为基本数据类型和引⽤数据类型,但是基本数据类型怎么能够称为对象呢?于是 Java 为每种基本数据类型分别设计了对应的类,称之为包装类(Wrapper Classes),也有地⽅称为外覆类或数据类型类。

我们来看下基本类型对应的包装类

java面试技巧:Integer和int的那些事⼉_包装类

两个维度分析:

从内存占⽤⻆度:包装类是对象,除了基本数据以外,还需要有对象头。所以包装类占的空间⽐基本类型⼤。

从处理速度⻆度:基本类型在内存中存的是值,找到基本类型的内存位置就可以获得值;⽽包装类型存的是对象的引⽤,找到指定的包装类型后,还要根据引⽤找到具体对象的内存位置。会产⽣更多的IO,计算性能⽐基本类型差。

因此在开发中,如果需要做计算,尽量优先使⽤基本类型。

那么⼤家思考⼀个问题:Java为什么还要设计出包装类来使⽤?⽬的是什么?

为什么使⽤包装类

在Java开发中,特别是在企业中开发的时候处理业务逻辑的过程中,我们通常都要使⽤Object类型来进⾏数据的包装和存储,Object更具备通⽤的能⼒,更抽象,解决业务问题编程效率⾼。⽽基本类型的包装类,相当于将基本类型“包装起来”,使得它具有了对象的性质,并且为其添加了属性和⽅法,丰富了基本类型的操作。特别是:Java的泛型,我们的基本数据类型并不能和泛型配合使⽤,因此要想配合泛型使⽤也得保证类型可以转换为Object。

同样的我们今天要说的Integer就是int的包装类,除了提供int类型的字段进⾏存储外,还给我们提供了基本操作,⽐如数学运算、int和字符串之间的转换等,我们可以来看看:

 

java面试技巧:Integer和int的那些事⼉_包装类_02

 

 

java面试技巧:Integer和int的那些事⼉_编程语言_03

 

 

java面试技巧:Integer和int的那些事⼉_包装类_04

 

我们可以看到Integer中的⽅法前⾯都有M,代表⼤部分⽅法是静态⽅法,可以直接使⽤,并且⾥⾯还有 很多的变量都是使⽤了final进⾏修饰:

 

java面试技巧:Integer和int的那些事⼉_数据结构_05

 

变量⾥⾯的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机制,没错这就是接下来我们要讲的 ⾃动装箱/⾃动拆箱 机制

⾃动装箱

平时我们写代码的过程中,⽐如定义⼀个变量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(包括端点)范围内的值,并可以缓存此范围之外的其他值

缓存设计

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 property

int 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_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;//配置⽂件中有值,并且满⾜上⽅条件对⽐及可更改high值

cache = new Integer[(high - low) + 1];//初始化cache数组,并且⻓度为127+128+1=256

int j = low;//j=-128

for(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对象,减少了内存占⽤。

⾃动拆箱

什么情况下Integer会⾃动拆箱呢,⽐如下⾯的代码:

Integer i = new Integer(10);

int j = 20;

System.out.print(i == j);

由于i是integer类型,j是基本类型,当两者需要进⾏⽐较的时候,i 就需要进⾏⾃动拆箱为int,然后进⾏⽐较;其中⾃动拆箱使⽤的是 intValue() ⽅法 。

看看源码,直接返回value值即可:

 

java面试技巧:Integer和int的那些事⼉_编程语言_06

 

/**

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> {

 

java面试技巧:Integer和int的那些事⼉_数据结构_07

 

Number 是⼀个抽象类,主要表示基本类型之间的转换。

好了,到这⼉就基本上把Integer相关的核⼼源码看完了,同时也能清晰的知道包装类,以及⾃动装箱和⾃动拆箱的使⽤以及原理。

⼆. 常⻅⾯试题

Integer和int的区别:

1、Integer是int的包装类,int则是java的⼀种基本数据类型 2、Integer变量必须实例化后才能使⽤,⽽int变量不需要 3、Integer实际是对象的引⽤,当new⼀个Integer时,实际上是⽣成⼀个指针指向此对象;⽽int则是直接存储数据值 4、Integer的默认值是null,int的默认值是0

常⻅问答:

问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);

}

现在我们再来看⽂章开头的时候这个问题,⼤家能说出答案了吗? 答案: a==b 为true; c==d为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. ⼤家可以下来⾃⼰好好思考下为什么会得到这个答案

标签:java,int,cache,value,127,Integer,100
From: https://blog.51cto.com/u_8238263/6025164

相关文章

  • java四大引用详解!
    什么是java四大引用? 是JDK1.2版本开始引入,把对象的引用分为4个等级,我们平时学习的就是四种的第一级的强引用,说白了,就Objecto=newObject(),四个引用分别是强引用、软引......
  • Java程序员必看:Solr vip竞价排名
    功能介绍本文将使用solr完成vip等级排名,这里并不是简单的按照vip等级排序。而是在使用solr条件查询(不使用排序)的时候将符合条件并且具有vip等级的数据显示在前面,这个时候......
  • Java:Path及Paths使用
    Java8Windows10-- 主要内容:Windows下测试,组合文件路径、Path转File等。 准备:D盘;D盘下bootweb目录(springboot项目);D盘下test.txt文件;D盘下其它目录及......
  • Java两大工具库:Commons和Guava(2)
    您好,我是湘王,这是我的51CTO博客。值此新春佳节,我给您拜年啦~祝您在新的一年中所求皆所愿,所行皆坦途,展宏“兔”,有钱“兔”,多喜乐,常安宁!开发中有一类应用会出现的比较多,就是文......
  • Java两大工具库:Commons和Guava(2)
    您好,我是湘王,这是我的博客园。值此新春佳节,我给您拜年啦~祝您在新的一年中所求皆所愿,所行皆坦途,展宏“兔”,有钱“兔”,多喜乐,常安宁!   开发中有一类应用会出现的比较......
  • JavaGuide--基础篇
    包装类型的缓存机制了解么?Java基本数据类型的包装类型的大部分都用到了缓存机制来提升性能。Byte,Short,Integer,Long这4种包装类默认创建了数值[-128,127]的相应类......
  • IDE中自带的java springboot项目的密码加密和解密
    IDE里搜这个类org.jasypt.intf.cli.JasyptPBEStringEncryptionCLI,跑类的main方法进行加密参数:input=你的明文密码password=固定你自己公司的某个固定值algorithm=PBEWi......
  • JavaScript写一个连连看的游戏
    天天看到别人玩连连看,表示没有认真玩过,不就把两个一样的图片连接在一起么,我自己写一个都可以呢。使用Javascript写了一个,托管到github,在线DEMO地址查看:​​打......
  • Delete `␍`eslint(prettier/prettier) 错误
    拉完代码之后所有行尾报错Delete␍,查询了一下,是因为mac和windows换行符差异问题,最简单的方法是在根目录下添加.editorconfig文件,大概是个统一缩进符、换行符之类的代码风......
  • JAVA加解密之AES
      <!--AES加密--><dependency><groupId>org.bouncycastle</groupId><artifactId>bcprov-ext-jdk16</artifactId><......