byte[]與String互轉引發的血案

String s = "HelloWorld";
byte[] b = s.getBytes();
System.out.println(new String(b));

看到上面的代碼,可能有同學會問了,這不就是JAVA的基本操作嗎,你老張有什麼好講的?

既然這樣,老張要考考大家,猜一下下面的代碼執行之後會輸出怎樣的結果。

public class Hello {
    public static void main(String[] args){
        String src = "HelloWorld";
        String dest = encrypt(src);
        System.out.printf("原來字符轉爲字節的長度爲:%d\n", src.getBytes().length);
        System.out.printf("加密字符轉爲字節的長度爲:%d\n", dest.getBytes().length);
    }


    /*爲了String進,String出,做了一次封裝*/
    private static String encrypt(String s){
        byte[] b = encrypt(s.getBytes());
        return new String(b);
    }


    /*這裏只是用位移演示加密,字節進,字節出*/
    private static byte[] encrypt(byte[] byteArr){
        for (int i=0; i<byteArr.length; i++){
            byteArr[i] <<= 1;
        }
        return byteArr;
    }
}

現在揭曉答案:

原來字符轉爲字節的長度爲:10
加密字符轉爲字節的長度爲:26

不知道各位同學有沒有猜對,說來慚愧,老張剛剛踩過這個坑。

事情的起因是這樣的,由於Java沒有內置的RC4加密,老張需要自己封裝實現,實現的過程中用到了字節和字符的互相轉換。因爲RC4只是在針對的byte[]上進行位移操作,所以其輸入輸出的字節長度應該是相等的。但是老張爲了使加密能夠應用於字符串,用字符串對加密方法做了一層封裝。問題就出在這一層封裝上。

且聽老張給你慢慢道來。

什麼是字節?

位是計算機內部的最小數據儲存單位,8位就組成了1字節,也就是java中的byte。

什麼是字符?

字符是指字母、數字、特殊符號的集合,也就是java中的char和String。

字節怎麼就變成了字符?

答案是字符編碼。比較出名的字符編碼是ascii、gb2312、utf-8等。其中ascii和gb2312是定長字符編碼,一個字符分別佔用1字節、2字節,而utf-8是變長字符編碼,最短爲1字節,最常爲4字節。

以ascii爲例,字母A在計算機中的存儲爲0b0100 0001。

到這裏可能有同學已經知道老張一開始天真在哪裏了?

如果只是字符串轉爲字節流之後又接着轉爲字符串也沒什麼問題。老張天真就天真在對utf-8得到的字節流做了位移操作之後,還期望能夠用utf-8重新解析字節流。

敲黑板:Java中String內置的public String(byte[] bytes)和public byte[] getBytes()對於不合法的utf-8字節流在解析時會增刪字節。

希望各位同學引以爲戒!

最後如何避免在使用加密算法時出現字節和字符的異常轉化,歡迎各位同學能夠留言,有需要RC4加密代碼的也可以在後臺留言。

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