Kotlin入門(17)等式判斷的情況
話說等式可是編程語言最基本的表達式之一,不管哪種高級語言,無一例外都采用雙等號“==”判斷兩個變量是否相等;就算是復雜的對象,在Java中也可通過equals函數判斷兩個實例是否相等。按理說這些能夠滿足絕大多數場合的要求了,那麽Kotlin又給等式判斷加入了哪些新概念呢?下面就讓我們好好探討一下具體業務中的等式判斷。
結構相等
基本數據類型如整型、長整型、浮點數、雙精度數、布爾型,無論是在C/C++還是在Java抑或是在Kotlin,都使用雙等號“==”進行兩個變量的相等性判斷。至於字符串類型,則比較特殊,因為最早C語言是在內存中開辟一塊區域,利用這塊區域存儲字符串,並返回一個字符指針指向該區域的首地址,此時如果對兩個字符指針進行“==”運算,結果是比較兩個指針指向的地址是否相等,而非比較兩個地址存儲的字符串是否相等;所以C語言判斷兩個字符串是否相等,用到的是strcmp函數;Java參考了C++,雖然不再使用字符指針,而使用String類型表示字符串,但是Java判斷兩個字符串是否相等,采用了equals函數,從一個函數換成另一個函數,仍然是換湯不換藥,沒有本質上的改變。
現在Kotlin痛定思痛,決心要革除這種沿襲已久的積弊,反正都把字符串當作跟整型一樣的基本數據類型了,何不直接統一相關的運算操作符?因此,既然整型變量之間使用雙等號“==”進行等式判斷,字符串變量之間也能使用雙等號“==”來判斷;以此類推,判斷兩個字符串是否不相等,通過不等運算符“!=”即可直接辨別。從Java到Kotlin,改變後的等式判斷表達式如下表所示:
判斷兩個字符串是否相等 strA.equals(strB) -> strA == strB
判斷兩個字符串是否不等 !strA.equals(strB) -> strA != strB
下面是個Kotlin判斷字符串相等性的代碼例子:
val helloHe:String = "你好" val helloShe:String = "妳好" btn_equal_struct.setOnClickListener { if (isEqual) { tv_check_title.text = "比較 $helloHe 和 $helloShe 是否相等" //比較兩個字符串是否相等的Java寫法是 helloHe.equals(helloShe) val result = helloHe == helloShe tv_check_result.text = "==的比較結果是$result" } else { tv_check_title.text = "比較 $helloHe 和 $helloShe 是否不等" //比較兩個字符串是否不等的Java寫法是 !helloHe.equals(helloShe) val result = helloHe != helloShe tv_check_result.text = "!=的比較結果是$result" } isEqual = !isEqual }
其中“==”的判斷結果如下面左圖所示,“!=”的判斷結果如下面右圖所示。
推而廣之,不單單字符串String類型,凡是Java中實現了equals函數的類,其對象實例均可在Kotlin中使用“==”和“!=”進行等式判斷。這種不比較存儲地址,而是比較變量結構內部值的行為,Kotlin稱之為結構相等,意即模樣相等,通俗地說就是一模一樣。
引用相等
有時候僅僅判斷兩個變量值是否相等,並不足以完成某種一致性判斷,現實生活中還有更嚴格的真偽鑒定需求,比如真假美猴王、文物的真品與贗品、蘭亭集序的真跡與摹本等等。倘若按照結構相等的判斷標準,復制品和真品在外觀上沒有區別,毫無疑問就是相等的。但這個相等的結果明顯與大眾的認知相悖,因為真品是唯一的,復制品再怎麽逼真也不可能與真品等價,所以結構相等並不適用於真偽鑒定,如何判斷真偽需要另一種由內而外全部相等的判斷準則,該準則叫做引用相等,意思是除了值相等以外,還要求引用的地址(即存儲地址)也必須相等。
在Kotlin中,結構相等的運算符是雙等號“==”,那麽引用相等的運算符便是三個等號“===”,多出來的一個等號表示連地址都要相等;結構不等的運算符是“!=”,相對應的,引用不等的運算符是“!==”。不過在大多數場合,結構相等和引用相等的判斷結果是一致的,下面列出常見的幾種等式判斷情景:
1、對於基本數據類型,包括整型、浮點數、布爾型、字符串,結構相等和引用相等沒有區別;
2、同一個類聲明的不同實例,如果不是每個屬性都相等,則其既是結構相等,又是引用相等;
3、同一個類聲明的不同實例,如果equals校驗的每個屬性都相等(譬如通過clone方法克隆而來),則其結構相等,但引用不等;
為詳細說明以上的等式判斷,下面給出具體的代碼例子,利用系統自帶的時間Date類演示一下結構相等和引用相等的區別:
val date1:Date = Date() val date2:Any = date1.clone() //從date1原樣克隆一份到date2 btn_equal_refer.setOnClickListener { when (count++%4) { 0 -> { tv_check_title.text = "比較 date1 和 date2 是否結構相等" //結構相等比較的是二者的值 val result = date1 == date2 tv_check_result.text = "==的比較結果是$result" } 1 -> { tv_check_title.text = "比較 date1 和 date2 是否結構不等" //結構不等比較的是二者的值 val result = date1 != date2 tv_check_result.text = "!=的比較結果是$result" } 2 -> { tv_check_title.text = "比較 date1 和 date2 是否引用相等" //引用相等比較的是二者是不是同一個東西,即使克隆的一模一樣也不是一個東西 val result = date1 === date2 tv_check_result.text = "===的比較結果是$result" } else -> { tv_check_title.text = "比較 date1 和 date2 是否引用不等" //引用相等倒過來便是引用不等 val result = date1 !== date2 tv_check_result.text = "!==的比較結果是$result" } } }
上述代碼的date2從date1克隆而來,所以二者的值是完全一樣的,區別僅僅是存儲的地址不同。接著使用雙等號“==”以及“!=”進行結構判斷,運算結果為相等,詳細結果如下圖所示。
繼續使用三等號“===”以及“!==”進行引用判斷,運算結果卻是不等,詳細結果如下圖所示。
以上的實驗結果,證明了引用相等校驗的是變量的唯一性,而結構相等校驗的是變量的等值性。
Kotlin入門(17)等式判斷的情況