专业编程基础技术教程

网站首页 > 基础教程 正文

?试之Integer和int的那些事?

ccvgpt 2024-08-06 12:37:07 基础教程 10 ℃

?试之Integer和int的那些事?

概序
?. Java包装类、装箱和拆箱
1.1 包装类
1.2 为什么使?包装类
1.3 ?动装箱
1.4 缓存设计
为什么设计这个缓存?
?. 常??试题
2.1 Integer和int的区别:
2.2 常?问答:
问1:
问2:
问3:
问4:


概序

最近在招聘?试的过程中,考察?些候选?的基础掌握能?中发现,还是有?多数?了有1~3年的开发者在基础这块?掌握的不够牢靠,没有去思考过为什么这样做,以及这样做的原因是什么?那么今天我

?试之Integer和int的那些事?

们就来聊聊Java中的Integer和int,以及他们在?试中?般会如何考候选?呢?

?先我们来看如下的?些?试连环炮:

  • 开发中你在定义常量的时候,?般是?的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);

 }

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

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

答案在文章最后呦

?先来条华丽的分割线


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

1.1 包装类

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

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

两个维度分析:

  • 从内存占??度:包装类是对象,除了基本数据以外,还需要有对象头。所以包装类占的空间?基本类型?。
  • 从处理速度?度:基本类型在内存中存的是值,找到基本类型的内存位置就可以获得值;?包装类型存的是对象的引?,找到指定的包装类型后,还要根据引?找到具体对象的内存位置。会产?更多的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 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对象,减少了内存占?。

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{

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

 }

现在我们再来看?章开头的时候这个问题,?家能说出答案了吗?

答案: 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. ?家可以下来??好好思考下为什么会得到这个答案

引用地址:http://yun.itheima.com/jishu/295.html 来源:黑马程序员

最近发表
标签列表