【肥朝】還有這種操作?淺析為什麼要看原始碼

肥朝發表於2019-04-23

前言

很多人都有一個疑惑,為什麼面試都喜歡問原理,問原始碼.但是實際工作根本用不上,也就是大家常說的,面試造火箭,進去擰螺絲.我身邊也有不少朋友問過我,我給他們的回答是.如果不看原始碼,不懂原理,出了問題你怎麼解決?他們給我的答覆基本都是兩個字,"搜尋"

也確實,工作中大部分問題通過複製錯誤資訊搜尋都能解決,加上現在框架越來越多,拼積木式的程式設計方式加上搜尋引擎,讓越來越多人產生了開發是件很容易的事的錯覺.我也一直想舉一個搜尋幾乎搜不到,要看原始碼才能弄懂其中緣由的例子.

【肥朝】還有這種操作?淺析為什麼要看原始碼

正巧這件事發生在了去年8月份,我一個很好的朋友問了我這麼個問題,他說

為什麼我傳的是空字串,但是用Mybatis的if標籤判斷該空字串 == 0 竟然是成立的

【肥朝】還有這種操作?淺析為什麼要看原始碼

從我們的認知上來說,一個 空字串一個數字0 是不可能相等的.所以我第一反應是,他是不是用法不對?或者是他的業務程式碼其他地方干擾到了? 於是我決定寫了個最簡單的demo來進行測試.如下

【肥朝】還有這種操作?淺析為什麼要看原始碼

然後輸出結果如下:

【肥朝】還有這種操作?淺析為什麼要看原始碼

驚奇的發現,這個if標籤果然把空字串數字0判斷成了相等.

這裡我並不想騙大家,遇到這種問題,坦白說第一反應當然不是看原始碼啦,當然是開啟瀏覽器搜尋一下.我們搜尋的方向主要有兩個,一個是mybatis if標籤的判斷原理,一個是為什麼mybatis if標籤空字串和0是相等的.結果發現,並沒有找到我們要想的答案(大家可以自行搜尋一下).

當然雖然沒有搜尋到滿意的答案,但是我們卻發現了另一個例子.

我相信類似這種判斷的程式碼大家專案中應該出現了很多.

<if test="uid != null and uid != '' ">
</if>
複製程式碼

我們平時開發中,很多同事都是喜歡複製黏貼!

【肥朝】還有這種操作?淺析為什麼要看原始碼

那麼不假思索的複製黏貼到底會有什麼問題呢,我們來看下面這個例子

【肥朝】還有這種操作?淺析為什麼要看原始碼

這個判斷雖然是複製黏貼一把梭出來的,但是從我們的認知上來說,這個物件確實不是null,也不等於空字串,所以這個判斷應該是true的,但是執行結果如下:

【肥朝】還有這種操作?淺析為什麼要看原始碼

果然,這個又顛覆了我們的認知,但是如果你遇到的是案例2這種情況還比較好搜尋,還是能搜到解決方案,如下圖

【肥朝】還有這種操作?淺析為什麼要看原始碼

其實這兩個案例都是一個問題,那就是這個if標籤,把0和空字串判斷成了相等.

這個時候要敲黑板劃重點了,俗話說一朝被蛇咬十年怕井繩,雖然第二個例子我們有了解決方案,但是這些解決方案都是治標不治本,如果我們沒弄懂這其中的原理,那麼你心裡永遠是有一塊疙瘩的.你害怕下一次,又有奇奇怪怪的事情發生,只有弄懂原理,才能從根源解決問題,也就是解決一類問題,而不是某一個問題.

同時我也認識到,機會來了,終於找到一個為什麼要看原始碼的比較合適例子了

分析原始碼

由於鏈路比較長.這裡就不把debug過程展示了(對Mybatis執行流程不熟悉的,可以看看我之前的別怕看原始碼,一張圖搞定Mybatis的Mapper原理,然後順著執行流程debug

我們拿第一個例子來分析,因為兩個案例其實遇到的問題都是一樣的.

【肥朝】還有這種操作?淺析為什麼要看原始碼

【肥朝】還有這種操作?淺析為什麼要看原始碼

【肥朝】還有這種操作?淺析為什麼要看原始碼

【肥朝】還有這種操作?淺析為什麼要看原始碼

【肥朝】還有這種操作?淺析為什麼要看原始碼

如果上面看不懂,我這裡可以簡單描述一下:

首先他會獲取兩個判斷物件的型別,當拿一個字串和一個數字判斷的時候,因為型別不一樣嘛,當mybatis發現,這個字串是可以轉換成數字的,那麼就會把這個字串轉成數字,然後再和這個數字判斷.

那麼問題就來了,這個空字串會轉換成什麼數字呢?

從原始碼的這個

return s.length() == 0 ? 0.0D : Double.parseDouble(s);
複製程式碼

就可以看出,這個空字串,是會被轉成0的.所以現在一切豁然開朗.

但是原始碼是看了,問題還是沒有解決啊.他裡面其他型別判斷的原始碼這麼多,不可能全部看完,時間也不允許啊,萬一還有其他坑怎麼辦.由此可見,只看原始碼還是不夠的,還需要一些解決問題的分析思路,這就是為什麼網上原始碼解析的文章這麼多,我們還要關注一下肥朝的公眾號(id:feichao_java)

解決問題的思路

我們雖然看了原始碼,我們也知道了這個判斷的規則和我們想要的,是有出入的.但是關鍵是,怎麼解決問題嘛.很多人第一反應是,那就修改原始碼唄.但是坦白說,你只看了這麼一小片原始碼就貿然修改,確定能駕馭得住,確定不會引發其他問題?所以這個解決問題的思考方向,注意,我說的是方向,是非常重要的.

如果說到物件導向的三大特性,那麼大家想必都不會陌生.封裝繼承多型.但是物件導向的五大原則.那麼大家可能就稍微要陌生了.那就是

  • 單一職責
  • 開閉原則
  • 依賴導致原則
  • 介面隔離原則
  • Liskov替換原則

那我就說一下開閉原則,引用一下百度知道里面比較簡短的描述是這樣的

開放封閉原則,其核心思想是:軟體實體應該是可擴充套件的,而不可修改的。也就是,對擴充套件開放,對修改封閉的。

如果你對設計模式有所瞭解的話,就很能瞭解這句話的意義.如果對這個不理解的,可以看一下大話設計模式這種書中,是如何引入策略設計模式的.簡單的說是這樣的,如果你是用if判斷,那麼多增加一個需求,你就要多增加一個else if,那就是要修改程式碼了.但是好的設計應該是,多增加一個需求,我只需要多增加一個實現類,也就是一種策略.(如果還不清楚的同學,建議看看設計模式),其實SPI,也是包含這種開閉原則的思想的.

Mybatis這麼優秀的框架.人家自然明白麵向物件的五大原則,所以必定會遵循這個原則.也就是說,他一定會提供一個方式,讓你多增加一個類,然後這個類裡面,來自定義這個if的判斷規則.

解決方案

我們自定義一個類,就比如我取名為FeiChaoOgnl

【肥朝】還有這種操作?淺析為什麼要看原始碼

然後我們的寫法變成這樣

【肥朝】還有這種操作?淺析為什麼要看原始碼

那麼我們執行看看

【肥朝】還有這種操作?淺析為什麼要看原始碼

【肥朝】還有這種操作?淺析為什麼要看原始碼

只要把FeiChaoOgnl判斷方法補充完整,按照這個寫法,就算是複製黏貼一把梭,出問題的風險也大大降低

寫在最後

本文僅為冰山一角,上百篇原創乾貨還在路上掃描下面二維碼關注肥朝,讓天生就該造火箭的你,不再委屈擰螺絲!

【肥朝】還有這種操作?淺析為什麼要看原始碼

相關文章