Integer 我能和你交流一下吗?

一时失言乱红尘 2022-12-31 01:12 169阅读 0赞

前言

我的文章前言不是前言,基本上就是放一些跟文本无关的东西(选择性阅读)。

最近遇到个比较好玩的看客:

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM1Mzg3OTQw_size_16_color_FFFFFF_t_70

最近这一两个月,面试了快近百号人。

听到求职者最多说到的一句话是 :项目里面没用到,所以没有了解。

回应:

这个不同人有不同的想法,**,你们有什么想法,可以在评论去留下。欢迎大家留下自己的想法。**

而我被问的最多的一句话是: 这些东西从哪里可以了解 ?

回应:

现在这个网络时代,知识共享时代,学习成本是较低的。

从哪里可以了解? 那么举例说明: 从我的文章了解就是一个的途径。

扯远了, 回到该篇文章。

本篇文章内容(包括但是不限于):

  1. Integer 的拆箱装箱(配图+举例+编译解析)

2.Integer 的 部分源码解读

3.Integer 的一些使用注意点

4.列着列着不想列了,反正想到啥写啥吧


正文

拆箱和装箱

我想想怎么介绍好一些,要不先随便看点图吧。

有4个int 类型,值为 10的 小家伙 等待被处理。

202012270954226.png

② 设计了 专门用于装int 的 箱子 Integer。

20201227100909916.png

然后丢到一个编号为10的箩筐里面, 以后包装完10的小箱子都会丢到编号10箩筐里,

找int 10 的时候,只需要找编码10的箩筐就行,方便。

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM1Mzg3OTQw_size_16_color_FFFFFF_t_70 1

③ 又来了一个int 类型,值为 3 的 小家伙 ,也是要处理

20201227101515782.png

一样的,Integer箱子装起来,丢到对应箩筐里就好。

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM1Mzg3OTQw_size_16_color_FFFFFF_t_70 2

④ 陆陆续续地,各种各样值的int小家伙都被安排妥妥的。

⑤ 大大小小的箩筐堆得遍地都是。

于是乎,腾了一个仓库出来,不过存量有限。

箩筐编号 范围在 -128 ~127 ,就丢这个临时仓库里面。

不在这个范围里面的, 就不弄统一的箩筐了,单独包装个箱子,贴一个随机的编码就得了,意思意思

范围内的:

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM1Mzg3OTQw_size_16_color_FFFFFF_t_70 3

不在范围内的(区别对待哈哈哈哈哈):

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM1Mzg3OTQw_size_16_color_FFFFFF_t_70 4

⑥ 为什么范围定在 -128 ~ 127 ?

(1字节=8位(bit)

最小值:10000000 (-128)(-2^7)

最大值:01111111(127)(2^7-1) )

整理总结:

需要处理 int 类型的小家伙时, 我们需要找到对应的箩筐。

那么找箩筐就得去临时仓库。

根据什么找呢, 可知道咱们的规矩是 范围 -128 ~ 127 ,int类型的值符合范围的,必定在仓库里会有(指向) 对应的箩筐。

看到这里,一头雾水。 没关系,就是简单留个印象就行。 接着看后面的内容,慢慢会理解起来的。

  1. Integer 装箱 , 将一个基本数据 int 类型的值 转换 为对应的引用类型 Integer 的对象 (int -> Integer) :

核心方法 :Integer.valueOf();

手动装箱示例:

  1. int num =1 ;
  2. //手动装箱
  3. Integer numNew01 =Integer.valueOf(num);
  4. //手动装箱
  5. Integer numNew =Integer.valueOf(1);

好家伙,我只是做个示例,编辑工具直接提示,让我去掉没必要的装箱代码:
20201227110809606.png

为什么?

因为在JAVA 5 里 引入了特性 支持自动装箱和自动拆箱 。

行,那咱们继续看自动装箱:

  1. //自动装箱
  2. Integer numNew = 1;

装箱简单初识到此。

我们说事做事讲求证据,没证据说怎么装都行啊?!

ok,我们来看看证据 ,自动装箱的时候做了什么?

  1. public static void main(String[] args) {
  2. //自动装箱
  3. Integer numNew = 1;
  4. }

javap 一看究竟:

行,确实是自动装了,咱们赶场,看拆箱去。

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM1Mzg3OTQw_size_16_color_FFFFFF_t_70 5

  1. Integer拆箱 ,将一个引用类型 Integer 的对象 转换 为对应的 基本数据 int 类型的值 (Integer -> int) :

核心方法 : Integer.intValue();

手动拆箱示例:

  1. Integer numNew = 1;
  2. //手动拆箱
  3. int num = numNew.intValue();

是的,可以手动,但是没必要。因为 自动拆箱在java 5里面引入了。

  1. Integer numNew = 1;
  2. //自动拆箱
  3. int num = numNew;

一看究竟,好的确实是拆了 :

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM1Mzg3OTQw_size_16_color_FFFFFF_t_70 6

看到这,看客们应该对装、拆箱有了一些认识了,事不宜迟,我们进入大家最喜欢的源码环节:

Integer装箱方法,我们刚刚提到了,通过javap 分析也能知道

就是 Integer.valueOf();

那么我们直接到源码里面搜索 valueOf ,定位到我们需要看的源码部分:
watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM1Mzg3OTQw_size_16_color_FFFFFF_t_70 7

英文水平比较好的看客,看到这个图,其实心里面已经透亮了。

而跟我一样水平的看客应该也是存在的,那么咱们看下中文翻译(关键部分):

如果需要,通常应优先使用此方法。

构造函数{@link#Integer(int)},因为这个方法很可能通过缓存频繁请求的值。

此方法将始终缓存-128到127范围内的值,包含,并且可能缓存此范围之外的其他值。

自1.5

注释简洁明了, 1.5引入; 范围 -128~127 ; 允许配置范围; 优先调用该方法;

结合实例,开始debug,分析源码:

2020122713495081.png

进入断点, 在编译的时候自动装箱,调用了方法.valueOf() :

20201227135057992.png

这里是说,符合if条件的,那么就 返回 IntegerCache 里面的 cache 值 , cache(缓存),那就是说,符合条件的,从缓存里面拿出来就好。

那么不符合if条件的, 使用new ,那么意思就是单独处理了。

结论:

判断是否在-128~127区间内,是则返回相应的对象引用,不是则返回一个新实例化的对象。

if 条件 :

  1. if (i >= IntegerCache.low && i <= IntegerCache.high)

IntegerCache 是什么? 判断范围是 IntegerCache的 low值和high值之间。

IntegerCache 其实就是 存放箩筐的 临时仓库 , 也就是可以理解为缓存池。

还记得我们的临时仓库存放箩筐的规则是什么吗? 箩筐编码必须在 范围 -128~ 127 之间, 也就是 low值和high值之间 。

简单点进去IntegerCache的源码看一眼:

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM1Mzg3OTQw_size_16_color_FFFFFF_t_70 8

可以看到关于范围值的获取 , 大致说的就是默认是-128~127 , 但是high值也许是通过配置调整过的。

通过-XX:AutoBoxCacheMax=size修改 或者 通过java.lang.Integer.IntegerCache.high设置最大值

这个 IntegerCache 其实在Integer里是 静态内部类。

初始化的时候,就会对范围内的值进行逐个进行处理,放到 Integer cache[] 缓存数组里面 。 也就是说,箩筐、仓库应用的都有。

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM1Mzg3OTQw_size_16_color_FFFFFF_t_70 9

这么一来,当我们使用的时候,自动装箱,范围内的就是从缓存仓库里面取就完事了,够快。

注意点 一

Integer值的 比较

既然我们都看到这里了, 也注意到了这个范围的概念。

显然看客们心里必然有想法, 就是范围外的值,装箱后, 不在缓存池里。

使用 new , new大家熟悉吧,用了new 意味着 重新编辑了一个箩筐(分配内存)。

直接看代码:

值比较示例 1:

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM1Mzg3OTQw_size_16_color_FFFFFF_t_70 10

值比较示例2:

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM1Mzg3OTQw_size_16_color_FFFFFF_t_70 11

使用“==”比较两个包装类引用时,比较的是指向的引用地址。

两个值 都是 13 , 都在范围 -128 ~ 127之间, 使用 == 符合比较, 相同,true 。

两个值 都是 130 , 都不在范围 -128 ~ 127之间, 使用 == 符合比较, 相同,false。

为什么? 刚才看了源码了,

20201227143644449.png

那么既然知道了这个问题, 我们怎么去比较呢?

  1. 范围内 可以使用 == , 范围外 先转为int数值再比较。 干脆点,也就是可以理解为,统统都使用 .intValue再比较。

意思就是利用拆包,转化成 int 类型数值比较, 这样 使用 == 符合就非常正确。

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM1Mzg3OTQw_size_16_color_FFFFFF_t_70 12

  1. 是不是觉得上面说的方式好麻烦? 是的,Integer的作者也知道看客们嫌麻烦,所以Integer重写了 equal方法 :

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM1Mzg3OTQw_size_16_color_FFFFFF_t_70 13

可以看到,里面也是进行了intValue() ,所以我们可以放心使用 equal去进行值比较。

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM1Mzg3OTQw_size_16_color_FFFFFF_t_70 14

注意点 二

小心 null 导致 NPE异常

因为 Integer 是包装类,那么接收值的时候 存在null的情况。 如果是null,还去使用的话,那么就会出现空指针 NPE异常。

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM1Mzg3OTQw_size_16_color_FFFFFF_t_70 15

注意点 三

该篇文章是以 Integer为例做的介绍, 千万不要以为 其他包装类 Double 、Float 也是这个逻辑 ,自动装箱拆箱也是这些 缓冲池、范围等等。

不是 ! 不是 ! 不是 !

其他的包装类人家虽然也会自动装拆, 但是 ! 逻辑不一样!

举例 提醒:

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM1Mzg3OTQw_size_16_color_FFFFFF_t_70 16

为什么不是 true ? 因为人家的valueOf() 不一样!! 所以前往别把Integer的知识,完全往别的包装类上面理解。

可以看一眼,Double的 valueOf() :

20201227151649814.png

为什么Double不做缓存池? 不弄箩筐了吗? 不弄临时仓库了吗? 是穷吗?弄不起?

你细想, 因为是Double ,光是 1-2之间, 1.1,1.2,1.3 …. 1.11 ,1.12 这些精度, 你想想如果弄缓冲池,缓存的量多么恐怖。

再看一眼Boolean的 valueOf() :

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM1Mzg3OTQw_size_16_color_FFFFFF_t_70 17

这Boolean 不是true就是false ,所以人家啥缓存不缓存的,啥范围的都不需要考虑了,之间就给 定死判断返回得了。

扯远了, 要想了解其他包装类的一些知识,可以参考我本文上面的了解Integer过程,自己也去看一看代码~

上面很多东西说的都是装箱,那么我们继续说说拆箱。

上边内容里有简单提到, 拆箱, 以Integer为例子来说,就是intValue(),转化成为int类型数据进行使用。

使用起来没啥问题,intValue源码也简单直接:

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM1Mzg3OTQw_size_16_color_FFFFFF_t_70 18

那么我们也举一些平时也许会使用到的示例来加深理解:

示例1 :

Integer的数值 都在范围内

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM1Mzg3OTQw_size_16_color_FFFFFF_t_70 19

再看示例2:

把Integer的数值改为范围外

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM1Mzg3OTQw_size_16_color_FFFFFF_t_70 20

可以看到都没有影响, 因为什么呢?

原因有二,

1.使用到了 算数运算 ,所以会自动拆箱, 也就是 num1 + num2 会拆箱计算。 (细想,两个对象你运算啥呢? 肯定的转化 成int 运算了嘛,所以运算完一边其实已经是int类型数值了)

  1. == 判断 有一边是 基本数值类型,那么就会自动拆箱比较。

所以补充一个 场景 1的 图(算数运算):
watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM1Mzg3OTQw_size_16_color_FFFFFF_t_70 21

关于拆箱,我还想简单提一下, for循环里面使用注意。

其实几个数据自动拆箱装箱啥的,说实话,性能的影响可以忽略不计,但是积少成多,如果在for循环里面涉及到自动拆、装 比较多的逻辑代码,那么我们就需要注意一下了。

可以提前把该拆的先拆了(转化类型)。

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM1Mzg3OTQw_size_16_color_FFFFFF_t_70 22

到这,感觉Integer 交流的东西也七七八八了, 最后再一起看看日常使用的 方法好了。

Integer.valueOf()

Integer.parseInt()

看到这两个方法,大家是不是很眼熟。

因为日常使用了,我们经常会 将字符串 转为 Integer 或者int , 然而其实很多人在使用的使用,都没用特意去区分 (当然,随便用也没啥,影响不大)。

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM1Mzg3OTQw_size_16_color_FFFFFF_t_70 23

其实,我们稍微看一看源码,我就把简单的分析结合图片展示给看客们吧:

Integer.parseInt()

20201227161114448.png

Integer.valueOf()

20201227161328758.png

也就是说,如果你知道你目前需要使用转化返回的参数类型,那么你就可以直接调用相对于的方法,这样就不用 自动拆装去帮你再整一哈了。

好了那就先这样吧。

我要去干饭了。

大家有什么疑问或者想法,就评论区见吧。

发表评论

表情:
评论列表 (有 0 条评论,169人围观)

还没有评论,来说两句吧...

相关阅读

    相关 写一个冒泡排序

    当然可以。冒泡排序是一种简单的排序算法,它重复地走过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到