没想到 switch 语句居然有这么一个坑

  • 公司项目在灰度的过程中,测试这边给我反馈了一个崩溃,具体堆栈如下:

Process: xxx.xxx.xxx, PID: 27468
java.lang.NullPointerException: Attempt to invoke virtual method 'int java.lang.String.hashCode()' on a null object reference
    at xxx.xxx.xxx.xxx.MessageFragment.getSexType(MessageFragment.java:57)
    at xxx.xxx.xxx.xxx.MessageFragment.access$100(MessageFragment.java:22)
    at xxx.xxx.xxx.xxx.MessageFragment$1.onClick(MessageFragment.java:50)
    at android.view.View.performClick(View.java:7514)
    at android.view.View.performClickInternal(View.java:7491)
    at android.view.View.access$3600(View.java:846)
    at android.view.View$PerformClick.run(View.java:28733)
    at android.os.Handler.handleCallback(Handler.java:938)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:236)
    at android.app.ActivityThread.main(ActivityThread.java:8134)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:656)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:967)
  • 发现 MessageFragment 类中的 57 行是一个 String 调用 hashCode 的时候报空指针了,我回去看了一眼代码

bad3e9d0cb806075585996fc712937d0.png

  • 这个类 57 行中压根没有调用过 hashCode?看完我顿时陷入了沉思

  • 过了一会儿我的小脑袋瓜灵机一动,是不是 getSexTypesexString 参数为空导致的?但是如果 sexString 参数为空,应该走 default 语句才对啊?怎么可能会调用 hashCode 方法呢?更别说报空指针异常了?先不管它三七二十八,我先试验一下,实践出真理。

572b918e60ab9e8c3038e061a81cca3c.png

  • 于是乎,我将这个方法的参数直接改成了 null,结果一运行就真的复现了这个问题

  • 那么问题来了,我明明没调用 hashCode 方法,为什么它就是提示我有呢?

4859e14d7b751c5853247519497f5af7.png

  • 既然能复现,那么应该从哪里从手这个问题?我的小脑瓜又灵机一动,是不是编译器在编译的过程中修改了我的代码?我心想这种事情不太可能发生,但是实践出真理,先试了再说

  • 说干就干,我们都知道 apk 的类都是在 dex 文件里面的,而 dex 是由多个 class 类合并而成,那么现在就让我们在项目中的 build 文件夹中搜索刚刚出现崩溃的那个类

ed4f291e82ef955eac1401976519ed3b.png

  • 并把它拖动到 Android Studio 打开看看看

a5f5e049ecd2dfb52ef950eeca3bd2bc.png

  • 结果真的被我猜对了,此时此刻我的心情是五味杂陈,沉思许久后发出了感叹:居然还能这么玩,这波操作真是让我开了眼

  • 原来 Java JDK 1.8 支持 switch 判断 String 类型是这么来的,本质上还是走的 switch 判断 int 类型的逻辑,调用 hashCode 方法只不过想得出字符串的哈希码,而字符串的哈希码是通过将 String 分解成一个个 char,然后通过运算得出,所以相同内容的 String 对象的 hasCode 是一样的。

bb6fe32f2041dc05957cd6e3056fe116.png

  • 既然知道了这其中的原理,那么刚刚的崩溃问题要怎么处理比较好?我认为有两种方式

  • 第一种:用 String 作为 switch 的判断条件时,应当先进行判空

private int getSexType(String sexString) {
    if (sexString == null) {
        return 0;
    }
    int sexType = 0;
    switch (sexString) {
        case "男":
            sexType = 0;
            break;
        case "女":
            sexType = 1;
            break;
        default:
            break;
    }
    return sexType;
}
  • 第二种:可以换成 if else + equals 语句来判断

private int getSexType(String sexString) {
    if ("男".equals(sexString)) {
        return 0;
    } else if ("女".equals(sexString)) {
        return 1;
    }
    return 0;
}
  • 至于用哪一种,这里不做强制要求,大家可以看着来

Android技术讨论Q群:78797078



作者:Android轮子哥
链接:https://www.jianshu.com/p/d2d11118ec02

关注我获取更多知识或者投稿

a7ca3b7ee0b58a9ab8fea5be78e318d5.png

9b88fa1283da5b973ce84431a41af6e7.png

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值