Java 中又一個你天天使用,但是不一定知道的知識點
大家都知道當我們在進行條件判斷的時候除了可以使用 if-else 之外,還可以是用 switch,而且在 JDK 7 之后在 switch 中還增加了 String 類型的支持,如下代碼所示。
- public static void testSwitch(String language) {
- switch (language) {
- case "C++":
- System.out.println("C++");
- break;
- case "Java":
- System.out.println("Java");
- break;
- case "Python":
- System.out.println("Python");
- default:
- System.out.println("default");
- break;
- }
- }
如果還不知道可以這樣用的小伙伴,那你今天知道了,不過阿粉相信小伙伴都知道這個特性,但是這里阿粉提兩個問題,看看聰明的你能不能答出來。
如果 language 為 null,即 testSwitch(null) 會輸出什么?
swtich() 支持String 的原理是什么?
看到這里請停下來,思考五秒鐘。
- 5
- 4
- 3
- 2
- 1
好,我們來看下上面兩個問題,首先如果對于問題一你要是回答會輸出default 那么阿粉告訴你,這是錯誤的。不信的話,我們實踐一下,畢竟實踐是檢驗真理的唯一標準。
從上面的輸出我們可以看到,已經(jīng)報了空指針的異常了,到這里可能有些小伙伴就疑惑了,上面的代碼看起來沒什么特別的啊,null 傳進去應該走到 default 分支才對啊,為什么會報空指針呢?有這個疑問的小伙伴也不要捉急,看完第二個問題的答案,你就知道為什么了。
同樣的要搞清楚為什么問題一的答案是空指針,我們就需要知道 switch 中支持 String 的原理是什么。下面我們來看看第二個問題。首先我們將這個代碼通過 Javac 編譯一下,執(zhí)行命令:javac SwitchTest.java,我們就可以得到編譯后的 SwitchTest.class 文件,再通過反編譯我們可以得到下面的內容,這里反編譯可以直接將 class 文件拖進 idea 中即可。
- //
- // Source code recreated from a .class file by IntelliJ IDEA
- // (powered by FernFlower decompiler)
- //
- package org.fenixsoft.clazz;
- public class SwitchTest {
- public SwitchTest() {
- }
- public static void main(String[] var0) {
- testSwitch((String)null);
- }
- public static void testSwitch(String var0) {
- byte var2 = -1;
- switch(var0.hashCode()) {
- case -1889329924:
- if (var0.equals("Python")) {
- var2 = 2;
- }
- break;
- case 65763:
- if (var0.equals("C++")) {
- var2 = 0;
- }
- break;
- case 2301506:
- if (var0.equals("Java")) {
- var2 = 1;
- }
- }
- switch(var2) {
- case 0:
- System.out.println("C++");
- break;
- case 1:
- System.out.println("Java");
- break;
- case 2:
- System.out.println("Python");
- default:
- System.out.println("default");
- }
- }
- }
到這里相信大家就知道為什么了,很顯然 Switch 支持 String 底層的原理是使用了 String 的 hasecode 和 equals 方法。通過得到入?yún)⒆址?hasecode 來決定進入哪個分支。大家都知道 hasecode 的返回值是 int 類型,所以說即使傳入的參數(shù)類型的字符串,底層還是使用的整型來進行判斷的。
而且到這里,大家也知道了為什么問題一的答案是會出現(xiàn)空指針了,因為這里在調用 hasecode 的時候,很明顯會出現(xiàn)空指針異常。
這就告訴我們在進行 switch string 的使用的時候,一定要進行入?yún)⒌姆?NULL 校驗,這一點在阿里巴巴的手冊中也有明確的強制要求。
同時通過上面反編譯后的代碼,我們也可以看到,參數(shù) String 是區(qū)分大小寫的,因為里面使用了 equals 進行判斷,所以我們也要注意字符串的大小寫,避免出現(xiàn)問題。
為了驗證是真的是采用 hasecode ,我們可以將上面代碼中涉及到了幾個字符串的 hasecode 輸出出來驗證一下。
- public static void main(String[] args) {
- testSwitch(null);
- System.out.println("C++".hashCode());
- System.out.println("Java".hashCode());
- System.out.println("Python".hashCode());
- }
可以看到輸出的 hasecode 和反編譯后的 hasecode 是一致的。
看到這里的小伙伴我們再延伸一下,既然這里是在編譯時期就生成了 hasecode ,那說明我們不能傳入一個動態(tài)生成的字符串,也就是下面的寫法會無法通過編譯。
雖然看上去都是一個字符串,但是明顯這種形式是不行的,因為沒辦法在編譯的時候就獲得 hasecode,自然也就不可以這些寫了,相信小伙伴們在之前寫代碼的時候也遇到過這種情況,但是當時可能并不知道是為什么,只知道要定義個常量或者字符串字面量,相信看完這篇文章的你,就知道是為什么了。
總結一下今天阿粉帶大家看了一個 Switch String 類型參數(shù)的實現(xiàn)原理,有些知識點在我們平時工作中雖然會經(jīng)常用到,但是并不會深入去研究原理。