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加密代碼的也可以在後臺留言。