Java千問:Java位運算經典應用(三)

接上篇

五、字符串加密

在很多場合下,都需要給字符串進行加密,使字符串由”明文”變成”密文”。對字符串加密有很多種算法,其實我們利用位運算也可以實現簡單的加密效果。用位運算實現加密的原理很簡單,這裏爲大家講解一下。假設有兩個整數a和b ,a^b的結果爲c。我們可以認爲a就是原始數據,a與b進行異或運算所得到的c就是加密後的數據,b在加密過程中扮演着”密鑰”的角色。在不知道b值的情況下,如果只是知道c的值,任何人無法僅僅根據c的值反推出a的值,也就是說,如果我們只知道加密後的數據,而不知道密鑰,根本無法確切得知原始數據a的值到底是多少。如果想根據加密後的數據c來還原初始數據a,就必須用密鑰b來解密。解密的方法也很簡單,只要進行c^b的操作就可以了。其原理就是”a^b^b=a”,在這個等式中,”a^b”的結果就是c,所以”c^b=a”。
理解了加密和解密的最基本原理之後,我們再來說說如何具體對字符串實施加密操作。我們知道,位運算符只能對byte、short、int、long和char這幾種基礎類型的數據進行運算,對字符串這種引用類型的數據並不適用。既然字符串無法進行位運算,那麼該如何對字符串進行加密呢?我們知道,無論是圖片還是文本,在計算機當中都是以二進制數的形式進行存儲的。既然是二進制數,那麼每8位的二進制數,都可以轉換成一個byte類型的數據。而N個8位二進制,就可以轉換成一個byte數組。概括成一句話就是:任何形式的信息,在計算機當中都可以用byte數組來存儲和表示。
我們現在要對字符串進行加密,表示字符串的String類提供了一個叫做getBytes的方法,這個方法可以把字符串轉換成一個byte數組。我們讓數組中的每一個元素都與某個數key進行異或運算,就能得到一個全新的byte數組,這個全新的byte數組本質上就是加密後的字符串,而那個數字key,其實就是加密過程中的”密鑰”,如果我們想要還原字符串,根據之前講過的”c^b=a”這個等式,我們可以再次用key這個數字與那個全新的byte數組的每一個元素做一次異或運算就可以。字符串加密的完整代碼如下:

public static void main(String[] args)  {
    String initString = "你好";//原始字符串
    byte[] bytes = initString.getBytes();
    byte[] tranCodes = new byte[bytes.length];//用於保存每個加密後的字節
    byte key = 111;//密鑰
    System.out.println("原始字符串爲:"+initString);
    //加密過程
    for (int i = 0; i < bytes.length; i++) {
        tranCodes[i] = (byte)(bytes[i] ^ key);// 對每個字節進行加密
    }

    String encode = new String(tranCodes);//用加密後的字節數組創建字符串
    System.out.println("加密後的字符串:"+encode);//輸出加密後的字符串
    //解密過程
    for (int i = 0; i < bytes.length; i++) {
        bytes[i] = (byte)(tranCodes[i] ^ key);//對每個字節完成解密
    }

    String decode = new String(bytes);
    System.out.println("解密後的字符串:"+decode);//輸出解密後的字符串
    }

如果密鑰key的值爲111,程序運行效果如下圖

Java千問:Java位運算經典應用(三)
如果密鑰key的值爲121,程序運行效果如下圖

Java千問:Java位運算經典應用(三)

六、計算一個二進制數當中1的個數

我們知道,一個二進制數,每個位上只能有0和1這兩種情況。如果我們想計算出一個N位的二進制數,總共有多少個位上是1,該如何計算呢?我們可以把這個二進制數進行右移1位,然後再左移1位,如果經過兩次位移運算,這個二進制數仍然保持不變,那麼說明這個二進制數的最低位(也就是最右邊那1位)上的數字爲0,否則說明最低位爲1。有的小夥伴可能沒有弄明白這個原理,我們以一個8位的二進制數”00000101”作爲例子來說明。我們把該二進制數稱爲a。我們可以看到:a的最低位爲1。如果a右移1位,將得到” 00000010”,然後再把” 00000010”左移1位,按照”左移操作最右邊補0”的運算規則,可以得到運算結果爲” 00000100”,我們把這個運算結果稱爲b。可以看出,a與b並不相等。然而,假如a的值爲” 00000100”的話,也就是說,a的最低位爲0,那麼經過一次”右移再左移”,所得到的運算結果b仍然是” 00000100”。因此,一個二進制數經過一次”右移再左移”的操作,如果仍然能夠和原來的值相同,那麼說明這個二進制數的最低位爲0,否則最低位爲1。
現在的題目要求我們計算一個二進制數的各位總共有多少個1,而以上算法僅能判斷最低位是否爲1,那麼應該怎樣把一個二進制數上所有的1都統計一遍呢?還拿剛纔舉例所用的二進制數a來講解。我們可以首先定義一個計數器,命名爲count,並設count的初始值爲0。當我們把a進行一次”右移再左移”的操作之後,發現原始數字a和運算結果b並不相同,這說明a的最低位是1,而我們要做的事情正是計算a當中總共有多少個位上是1,於是我們就可以把計數器count加1。之後,我們再把a做一次無符號右移並賦值給a自身。這裏有兩個需要注意的細節。首先,無符號右移結束之後,有一個非常關鍵的操作”賦值給a自身”,這使得a會被重新賦值,從而a的值就變成了”00000010”。其次,我們對a進行賦值之前進行的那個右移操作是”無符號右移”,也就是給a的最左邊補的數是0。如果我們不斷的重複這個過程,直到a的值變爲”00000000”才停下來。在這個過程中,每次遇到最低位爲1的情況,就使計數器count的值加1。當運算徹底停止之後,通過count的值就可以得知a的各個位總共有多少個1。計算二進制數中各個位總共有多少個1的完整代碼如下:

public static void main(String[] args)  {
        int a = 7;
        int count=0;
        while(a!=0)
        {
            if((a>>1)<<1!=a) //對a進行"右移再左移",判斷其結果是否等於原來的a
            {
                ++count;
            }

            a = a>>>1;//完成1次判斷,對a進行無符號右移並把運算結果賦值給a自身
        }
        System.out.println("a轉換爲二進制數後,有"+count+"個1");
    }

(未完待續...)
如想系統學習Java編程,歡迎觀看我在本站的視頻課程。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章