Apache工具包方法——Hex.encodeHexString(byte[] data)原始碼淺析
最近正在研究加密的相關方法和思想,有時候會用到byte型別的陣列金鑰或者密文,由於經常會遇到要將這鬼東西與資料庫進行存取操作的情況,並且大多數情況都是將這樣的byte陣列轉化為字串進行儲存的,因此用到了題目中的API,現對其原始碼實現進行總結和思考。
/** * Used to build output as Hex */ private static final char[] DIGITS_LOWER = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; protected static char[] encodeHex(final byte[] data, final char[] DIGITS_LOWER) { final int l = data.length; final char[] out = new char[l << 1]; // two characters form the hex value. for (int i = 0, j = 0; i < l; i++) { out[j++] = DIGITS_LOWER[(0xF0 & data[i]) >>> 4]; out[j++] = DIGITS_LOWER[0x0F & data[i]]; } return out; }
原始碼如上。
原始碼中我們注意到了DIGITS_LOWER這個char[] 陣列,事實上這個encodeHex的實現原理是將data中的每個元素拆分為兩個十六進位制數,然後在DIGITS_LOWER中分別找到對應的表示字元,來組裝成一個char[]陣列,然後再通過new String(char[] chars) 方法轉化為我們需要的“十六進位制”字串。
一步一步來看。
首先data.length獲取到data陣列的元素個數(陣列長度也就是元素的個數),然後再初始化一個新的char陣列,out = new char[l << 1];這裡值得注意的是char陣列的長度,原始碼中用移位運算來表示,事實上在我上一篇文章中已經寫得很明確,將一個數左移一位等價於將這個數 ×2,也就是說這個char陣列的長度是data陣列的二倍!為什麼?原因如下:data中的每個元素都是byte型別,每個元素8個bit,分為高四位低四位,而每四位就可以表示一個0x0到0x15的十六進位制數字,因此我們想將data中的每個元素用兩個十六進位制的數字表示就必須初始化一個是data長度兩倍的char陣列,這就是out物件的長度是[l << 1]的原因。
我們在原始碼匯中也可以看到這樣的註釋// two characters form the hex value.
緊接著,for迴圈。我們可以在腦海中建立這樣一幅景象,兩個並列的陣列byte[] data和char[] out我們從data中取第一個元素,將其以二進位制的數字表示出來,然後拆分高四位低四位,分別找到對應的兩個十六進位制的字元表示,然後再塞入char[]陣列中,這就是這個for迴圈的功能!
0xF0 & data[i]根據“與運算”的邏輯規則,我們得知其目的是為了使得data[i]的低四位都變成0;然後>>>4無符號右移4位,取得高四位所表示的數值,我們可以換一種理解,“與”的目的是讓低四位變成0,然後右移是為了去掉高四位後面的四個0,這樣我們就拿到了高四位表示的值(我們已經知道二進位制的四位數的取值範圍就是0到15)。然後將這個高四位表示的值作為index找到對應的DIGITS_LOWER陣列中的字元,並賦值給out[j],然後++兩次,代表高位一次和低位一次,這樣,我們就成功的完成了一組高四位低四位的拆分、替換、重組,然後只要迴圈data陣列的長度就可以對每個byte元素進行相同的拆分重組操作了。
最後返回char[] out 。
這是一個非常簡單實用的byte[]陣列轉化為String的小方法,API的開發者巧妙的利用'0'到'f'這十六個字元“代表” 0 到 15這十六個十六進位制數,然後將byte元素逐一拆分並重組成一個新的char[]陣列。
以上是本人經過實踐之後對原始碼的分析和理解,喜歡的朋友記得點贊哦,作為一個工作僅兩年的小菜鳥來說誠然是不小的鼓勵,如果同行的朋友有什麼問題和建議,還請不吝賜教!