- 在开发测试的过程中,发现一个崩溃,具体堆栈如下:
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
的时候报空指针了,我回去看了一眼代码
这个类 57 行中压根没有调用过 hashCode?看完我顿时陷入了沉思
过了一会儿我的小脑袋瓜灵机一动,是不是
getSexType
的sexString
参数为空导致的?但是如果sexString
参数为空,应该走default
语句才对啊?怎么可能会调用hashCode
方法呢?更别说报空指针异常了?先不管它三七二十八,我先试验一下,实践出真理。
于是乎,我将这个方法的参数直接改成了
null
,结果一运行就真的复现了这个问题那么问题来了,我明明没调用
hashCode
方法,为什么它就是提示我有呢?
既然能复现,那么应该从哪里从手这个问题?我的小脑瓜又灵机一动,是不是编译器在编译的过程中修改了我的代码?我心想这种事情不太可能发生,但是实践出真理,先试了再说
说干就干,我们都知道 apk 的类都是在 dex 文件里面的,而 dex 是由多个 class 类合并而成,那么现在就让我们在项目中的 build 文件夹中搜索刚刚出现崩溃的那个类
- 并把它拖动到 Android Studio 打开看看看
结果真的被我猜对了,此时此刻我的心情是五味杂陈,沉思许久后发出了感叹:居然还能这么玩,这波操作真是让我开了眼
原来 Java JDK 1.8 支持
switch
判断 String 类型是这么来的,本质上还是走的switch
判断 int 类型的逻辑,调用hashCode
方法只不过想得出字符串的哈希码,而字符串的哈希码是通过将 String 分解成一个个char
,然后通过运算得出,所以相同内容的 String 对象的hasCode
是一样的。
既然知道了这其中的原理,那么刚刚的崩溃问题要怎么处理比较好?我认为有两种方式
第一种:用 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;
}
- 至于用哪一种,这里不做强制要求,大家可以看着来