zoukankan      html  css  js  c++  java
  • 一条语句引发的思考:装箱和拆箱,空指针的类型转换

    最近做CodeReview,发现了一位已经离职同事写的代码,大致如下,令人费解。(其中map是Map<String, Object>)

    1 try {
    2             
    3             int count = (Integer) map.get("count");
    4             
    5         } catch (NullPointerException e) {
    6             // do something.
    7         }

    先不说这样写好不好,引起我兴趣的是,map这个变量,已经在上文判断是否为空指针了,map.get("count")也不会抛出空指针异常。为什么这里还要判断?

    经过一番搜索学习,想要理解上面的语句,那么你需要了解以下知识点。

    1. null 与 对象的转换

    null既不是对象也不是一种类型,它仅是一种特殊的值,你可以将其赋予任何引用类型,你也可以将null转换成任何类型。例如下面的代码,是可以运行的。

    关于null的知识点,可以参考 Java中有关Null的9件事

    Integer a = (Integer) null;
    Double b = (Double) null;
    Boolean c = (Boolean) null;

    2.装箱和拆箱

    Java为每种基本数据类型都提供了对应的包装器类型,自jdk 1.5之后提供了自动装箱(autoboxing)和拆箱(unboxing).


    上面这个就没什么好讲的了。

    所谓装箱和拆箱,就是指基本类型和包装器类型的互相转换。

    装箱:基本类型->包装器类型;拆箱:包装器类型->基本类型。

    1 Integer integer = 1; //装箱
    2 int i = integer; //拆箱

    3. 装箱和拆箱的实现

    对上面的代码进行编译,查看字节码,如图所示:

    装箱的时候,使用静态的valueOf()方法;拆箱的时候,使用非静态的intValue()方法。

    经过测试,上述的所有类型,装箱都会调用静态的valueOf()方法,而拆箱使用非静态xxxValue()方法。

    4.一个小陷阱

    来看下面的代码,会是输出什么呢?

    1 Integer a = 1;
    2 Integer b = 1;
    3 Integer c = 200;
    4 Integer d = 200;
    5 System.out.println(a == b);
    6 System.out.println(c == d);

    Integer是引用类型,引用类型是要看引用的地址的,很明显这四个都不是同个对象,都打印false.

    然而……

    这里就涉及到一个缓存的问题。查看Integer的valueOf()代码,可以看到,在某个范围内,会从缓存取值,这样取出来的,就是同一个对象了。

     IntegerCache的范围一般是[-128,127]。(是否可以修改,待确认)

    经检查

    1)Integer, Byte, Long, Short都是从[-128, 127];Character是[0,127];Boolean是FALSE or TRUE.

    2)Double和Float没有缓存的概念

    3)通过直接创建的对象,不会从缓存中获取。

    1 Integer a = new Integer(1);
    2 Integer b = new Integer(1);
    3 System.out.println(a == b);

    打印false;

    5. 包装器的符号运算(以Integer为例)

    1)==,两边都是Integer,比较内存地址;存在一边是基本类型,比较数值大小

    2)+,转换成基本类型后相加

    这个就不证明了。 有兴趣按照上面的方式检查(javap -c xxxx)

    6. 问题分析

    回到最开始的问题,为什么会抛出空指针异常?

    1 int count = (Integer) map.get("count");

    1)map获得的值,有可能为null.

    2)null可以转换成所有类型,于是得到一个声明为Integer类型的变量,该变量实际上指向为空

    3)Integer转成int,发生拆箱,调用非静态的intValue()方法,而变量实际上为空,那么就会抛出空指针异常

  • 相关阅读:
    实验-继承&super.doc
    Python库
    Github高级搜索
    代码报错记录
    编程问题解决
    百科
    【Android】添加依赖包
    【Android】导航栏(加图片icon)和不同页面的实现(viewpager+tablayout)
    【Android】Android Studio真机调试的问题统整
    【AD】自己画板的备忘
  • 原文地址:https://www.cnblogs.com/kingsleylam/p/6006183.html
Copyright © 2011-2022 走看看