平时的小细节,总能在关键时刻酿成线上事故,最近在代码中使用了Integer的自动拆箱功能,结果NPE(NullPointException)了,悲剧啊。。。

一、何为自动拆箱

要说自动拆箱,就必须说自动装箱,当然这里拆箱和装箱不是平时的把一个东西放到纸箱子里进行包装的意思,这里的装箱也有包装的意思,但包装的东西却不是可以看的见的物件。

学过java的都知道,java中的数据类型分为基本类型和引用类型,基本数据类型中有byte,short,int,long,char,folat,double,boolean,每种基本类型又有其包装类Byte,Short,Integer,Character,Float,Double,Boolean,这些包装类也可以称之为引用类型,这里的装箱和拆箱说的就是八种基本数据类型和其包装类之间的故事,自动装箱和自动拆箱有好处也有不好的地方,用不好就会造成很大的伤害。

二、事故复现

1、事故重现

这里计划用简单的代码,复现下自动拆箱的NPE,

这里有一个Person类,里边有以下的属性,注意这里我把其age属性的数据类型设置为了Integer

package com.my.unbox;/*** @author wangcj5* @date 2022/4/16 11:09*/
public class Person {/*** 年龄*/private Integer age;/*** 姓名*/private String name;/*** 家庭住址*/private String address;public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getAddress() {return address;}public void setAddress(String address) {this.address = address;}
}

下面直接上测试类

package com.my.unbox;import java.time.Period;
import java.util.Objects;/*** @author wangcj5* @date 2022/4/16 11:11*/
public class TestPerson {private static final int YONG_MAN=18;private static final int OLD_MAN=60;public static void main(String[] args) {//正常情况下Person person=new Person();person.setAge(16);System.out.println(isYoung(person));//非正常情况下Person person1=new Person();System.out.println(isYoung(person1));}/*** 通过年龄判断一个人是否为少年,小于18* @param person* @return*/private static boolean isYoung(Person person){if(Objects.nonNull(person)){if(YONG_MAN<person.getAge()){return true;}}
return false;}
}

小伙伴们看,测试类也很简单,里边有个方法,判断一个Person对象是否为年轻人,通过其age属性进行判断,那么测试结果如下,

false
Exception in thread "main" java.lang.NullPointerExceptionat com.my.unbox.TestPerson.isYoung(TestPerson.java:32)at com.my.unbox.TestPerson.main(TestPerson.java:22)Process finished with exit code 1

在第32行发生了NPE,第32行处的代码如下,

if(YONG_MAN<person.getAge()){

下面来分析下这行代码,首先person肯定不为null,因为上面已经进行了非空判断,那么就说person.getAge()为null,从调用的地方第22行

System.out.println(isYoung(person1));

也就是说person1不为null,那么就是person1中的age属性为null,由于这里仅仅new了一个person对象未对age赋值,那么对于Integer属性的age默认为null,这里也就不奇怪了,问题回到了比较的地方,一个int类型的值和null进行数学比较,这里就会发生拆箱,即把为null的age进行拆箱,在这里发生了NPE。现在就明白了在进行拆箱的时候如果被拆得对象为null肯定会NPE,那么java是如何拆箱的,继续往下看

2、拆箱的本质

要了解拆箱的本质肯定不能草草了事,通过反编译后的代码看下,把TestPerson进行反编译,使用javap命令,

PS C:\05code\Design\target\classes\com\my\unbox> javap -c -p TestPerson.class

得到下面的结果,重点看第32行拆箱的部分,

看上图红框内的,看后面的注释,第一句是调用getAge()方法得到其值,第二句是调用了Integer.intValue()方法,也就是说拆箱调用的Integer.intValue()方法,现在看下该方法的源码,

  public int intValue() {return value;}

看到吗,就是直接返回value。回到问题的本质为什么会发生NPE,也就是在拆箱时调用intValue()方法由于到到age为null,即,null.intValue(),这不就发生了NPE。

自动拆箱 实际调用的是intValue()方法

下面看自动装箱,看一个int类型的变量如何称为Integer

public class TestBoxing {public static void main(String[] args) {Integer integer=10;}
}

反编译后,

可以看到调用了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);}

自动装箱 实际调用的静态方法valueOf(int i)方法

三、避坑

上面通过一个小例子,分享了自动拆箱中可能发生的问题,那么应该如何必坑,

1、在自动拆箱的地方进行为null判断;

2、比较的时候尽量做到比较符合两端数据类型一致;

3、平时勤学苦练;

四、总结

自动拆箱时由于调用的是intValue方法,所以如果调用方本身是null的话,肯定会NPE,所以在发生自动拆箱的地方一定要多注意。

自动装箱调用的是静态方法valueOf,自动装箱其实还隐藏了一个更大的秘密,你知道吗,下期见。

编码处处有bug,生活处处有惊喜。对待代码要有敬畏之心,多总结经验。

java的自动拆箱会发生NPE相关推荐

  1. java三元表达式因自动拆箱导致的NPE问题

    开发中发生的奇怪的问题,类似如下的代码NPE了... boolean flag = false; Integer a = null; Integer n = flag ? 1 : a; 原来是在计算三 ...

  2. java 包装类缺点_Java 自动拆箱和自动装箱学习笔记

    Java 自动拆箱和自动装箱学习笔记 详情参考以下 1. 概述 Java 中的自动装箱和自动拆箱算是一种语法糖,也就是在编译阶段编译器在合适的情况下帮我们的做了自动拆箱和自动装箱. 众所周知,Java ...

  3. java自动装箱和自动拆箱

    Java自动装箱和自动拆箱是Java语言的一颗语法糖. 下面说一下java的自动装箱和拆箱的例子 1. 深入理解java虚拟机上的一个例子 public static void testJvmBook ...

  4. java中的自动拆箱和装箱(以及NEP问题)

    java中的自动拆箱和装箱 1.回顾知识点 java中的8种基本数据类型,可以分为三类 字符类型 char 布尔类型 boolean 整数类型 byte , short , int , long 浮点 ...

  5. 自动拆箱时遇到的NPE问题

    目录 什么是自动拆箱 遇到的NPE问题 问题原因 总结 什么是自动拆箱 拆箱:是将包装类型转换为基本数据类型 遇到的NPE问题 这里有一个简单的Person类,只有姓名和年龄的属性和get(),set ...

  6. Java进阶之自动拆箱与自动装箱

    序. java基本类型介绍 java中,基本数据类型一共有8种,详细信息如下表: 类型 大小 范围 默认值 byte 8 -128 - 127 0 short 16 -32768 - 32768 0 ...

  7. java char的包装对象,Java 从Character和char的区别来学习自动拆箱装箱

    本文结构 1.Character和char 的区别: 2.自动拆箱装箱java 1.Character和char 的区别: Character是类,char基本数据类型.数组 在java中有三个类负责 ...

  8. java 自动装箱自动拆箱_自动装箱和自动拆箱

    自动装箱和自动拆箱 Java 提供了 8 种基本数据类型,每种数据类型都有其对应的包装类型,包装类是面向对象的类,是一种高级的数据类型,可以进行一些比较复杂的操作,它们是引用类型而不再基本类型了. 基 ...

  9. 第三次学JAVA再学不好就吃翔(part64)--自动装箱和自动拆箱

    学习笔记,仅供参考 自动装箱和自动拆箱 装箱:把基本类型转换为包装类类型 int x = 100; Integer i1 = new Integer(x); 拆箱:把包装类类型转换为基本类型 int ...

最新文章

  1. pyqt4+chatterbot实现简单聊天机器人程序
  2. 艰难就业季,2020 AI算法岗春招汇总 面经大全来了!!!
  3. 16windows_16_combo组合框
  4. Play Framework入门引导
  5. 不用虚拟机直接在线用的 Linux,统统都在这里!
  6. 关于SOAP的几篇文章
  7. androidbyte数组使用_android byte的用法
  8. mybatis中#{}和${}的区别及order by的sql注入问题
  9. UOJ291 BZOJ4785 ZJOI2017树状数组
  10. 查询子串_你知道什么是 MySQL 的模糊查询?
  11. DWM1000 定位操作流程--[蓝点无限]
  12. 电脑一键装机软件哪个好 目前干净的一键重装系统软件推荐
  13. xtdpdgmm:动态面板数据模型一网打尽
  14. CTC blank 理解
  15. 求x的n次方编程_C++编程X的N次方程序
  16. java炫酷龙卷风源码,龙卷风's Blog
  17. 十进制和二进制相互转换
  18. 使用 Python 第三方库发送电子邮件
  19. 微软行星云计算Planetary Computer——previsa南美洲亚马逊雨林森林损坏系统AI智能评估
  20. codeforces 赛后总结

热门文章

  1. 优雅高效的Mac环境配置教程:从零开始八步走
  2. 前端小帆( Promise的原理 )
  3. 『金融帝国实验室』(Capitalism Lab)_v8.2.00大型更新发布前瞻(一)——新服务设施『快餐店』
  4. leetcode206 反转列表
  5. 今天换个画风,来聊聊广告吧
  6. 奇异值分解 水印 matlab,基于奇异值分解的数字图像水印算法研究毕业论文
  7. Ubuntu root切换
  8. win10 XBox无法录屏--已解决
  9. 面试必问:Spring循环依赖
  10. “ Infinity”是默认超时错误