平时的小细节,总能在关键时刻酿成线上事故,最近在代码中使用了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.NullPointerException
at 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. 空指针异常 自动拆箱 防止 NPE,是程序员的基本修养 本手册明确防止 NPE 是调用者的责任。

    空指针异常 空指针异常是指java中的异常类.   中文名 空指针异常 外文名 NullPointerException 当应用程序试图在需要对象的地方使用 null 时,抛出该异常.这种情况包括: ...

  2. JavaStudy——Java之自动拆箱与自动装箱

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

  3. Java语法糖2:自动装箱和自动拆箱

    前言 一开始想学学自动拆箱和自动装箱是被这个名字吸引到,听上去好像很高端的样子,其实自动拆箱.自动装箱是很简单的内容. 自动拆箱和自动装箱 Java为每种基本数据类型都提供了对应的包装器类型.举个例子 ...

  4. java 自动装箱自动拆箱

    1.Java数据类型 在介绍Java的自动装箱和拆箱之前,我们先来了解一下Java的基本数据类型. 在Java中,数据类型可以分为两大种,Primitive Type(基本类型)和Reference ...

  5. 转!!Java学习之自动装箱和自动拆箱源码分析

    自动装箱(boxing)和自动拆箱(unboxing)   首先了解下Java的四类八种基本数据类型   基本类型 占用空间(Byte) 表示范围 包装器类型 boolean 1/8 true|fal ...

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

    自动装箱 java执行Integer i = 100:编译器编译成Integer i = Integer.valueOf(100); Integer i = 100; //编译器编译成Integer ...

  7. Java中的自动拆箱装箱(Autoboxing&Unboxing)

    一.基本类型打包器 1.基本类型:long.int.double.float.boolean 2.类类型:Long.Integer.Double.Float.Boolean 区别:基本类型效率更高,类 ...

  8. 别说你不知道java中的包装类,wrapper type,以及容易在自动拆箱中出现的问题

    很多时候,会有人问你,你知道什么是包装类吗? 或者高端一点问你你知道,wrapper type,是什么吗? 然后你就懵逼了,学了java很多时候都不知道这是啥. 其实问你的人,可能只是想问你,java ...

  9. JAVA进阶之旅(一)——增强for循环,基本数据类型的自动拆箱与装箱,享元设计模式,枚举的概述,枚举的应用,枚举的构造方法,枚举的抽象方法

    JAVA进阶之旅(一)--增强for循环,基本数据类型的自动拆箱与装箱,享元设计模式,枚举的概述,枚举的应用,枚举的构造方法,枚举的抽象方法 学完我们的java之旅,其实收获还是很多的,但是依然还有很 ...

  10. java基础40 可变参数、自动装箱和自动拆箱

    一.可变参数 可变参数是jdk1.5新特性 1.1.可变参数的格式 数据类型...变量名 // 数据类型...变量名public static void sum(int...arr){ } 1.2.可 ...

随机推荐

  1. ASP.NET Core - 实现自定义WebApi模型验证 ModelState

    Framework时代 在Framework时代,我们一般进行参数验证的时候,以下代码是非常常见的 [HttpPost] public async Task<JsonResult> Sav ...

  2. WIN11 删除其它用户/账户

    WIN11 删除其它用户/账户 参考:https://support.microsoft.com/zh-cn/windows/%E5%9C%A8%E7%94%B5%E8%84%91%E4%B8%8A% ...

  3. 使用优启通 制作 WIN PE U盘时报BOOT.WIM 有毒的解决方法

    使用优启通 制作 WIN PE U盘时报BOOT.WIM 有毒的解决方法 1.打开"Windows Defender". 2.点击"病毒和威胁防护". 3.点击 ...

  4. EF MYSQL DB FIRST 出现2次数据库名

    环境:使用ADO设计器添加的数据库实体,运行时出现 :Table 'world.world.city' doesn't exist . world 是mysql的演示数据库. MySql.Data.E ...

  5. 【译】Visual Studio 17.10 发布了新版扩展管理器

    我们将更新的扩展管理器带给所有用户!在过去的一年里,我们已经将更新后的扩展管理器作为可选的预览功能提供,并一直期待您的反馈.基于您令人难以置信的反馈,我们现在准备从 Visual Studio 17. ...

  6. Cannot set properties of undefined (setting 'dataIndex')""

    前端写桑基图的时候碰到以上bug 原因是: 桑基图中的name值有重复的,把重复的name值去掉就好了

  7. 将链表以m长度为一组反转链表

    一群友分享的阿里面试题 1.将head链表以m为组反转链表(不足m则不反转): 例子:假设m=3. 链表 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> ...

  8. com.netflix.hystrix.exception.HystrixBadRequestException: null

    com.netflix.hystrix.exception.HystrixBadRequestException: null 排查方法:如果有多个feign接口的调用,可以在每个调用的方法加上try- ...

  9. Linux系统与网络管理

    0. 背景 0.1 Unix Unix诞生于1969年 特点 多任务 多用户 多平台 保护模式 可移植操作系统接口(POSIX) 0.2 Linux 与Unix关系 类Unix系统,完全按照Unix的 ...

  10. 如何应用 matrix3d 映射变幻

    如何应用 matrix3d 映射变幻 先上 demo 记得是在 2015 看到过的一个 html5 演示效果, 很惊艳 当时没明白如何实现,现在我会了,做一个类似的: 又弄了一个拖动的 demo 我数 ...