Java 輸出通過 InetAddress 獲得的 IP 地址數組

使用 InetAddress 獲取 IP 地址會得到一個 byte 數組

如果你直接輸出這個數組,你會發現 IP 地址中的某些位變成了負數

比如 61.135.169.105 會輸出成 61.-121.-87.105

仔細看一看,會發現 135 + 121 = 256,169 + 87 = 256


-_-! 怎麼個情況!


我首先想到的是 byte 類型向 int 類型轉換過程中出現了問題,後來發現,實際不然

因爲 Java 中沒有 unsigned 類型,所以byte、short、int、long 都是有符號的,所以根本就不存在隱式類型轉換出錯的問題。


既然說到了 Java 沒有 unsigned 類型,那麼 byte 是 8 位,所以表示範圍爲 -127 - 128,而 IP 一個段的表示範圍爲 0 - 255,終於找到了不對勁的地方了

IP 的一個段是一個 unsigned byte,這樣一個 unsigned byte 存入一個 signed byte 中當然會導致一些問題出現


分析一下:

35 的二進制編碼爲 1000 0111,最高位置爲 1

由於 byte 被認爲是 unsigned byte,所以最高位的 1 將會被解釋爲符號位,另外 Java 中存儲是按照補碼存儲,所以 1000 0111 會被認爲是補碼形式,轉換成原碼便是 1111 0001,轉換成十進制數便是 -121。

再看,65 的二進制編碼爲 0100 0001,由於小於 128,所以沒有將最高位置 1,0100 0001 的補碼還是 0100 0001,所以 65 不變。


分析這麼多,這個問題的解決方法其實很簡單,將 byte 變量與 0xFF 按位與即可,過程中 byte 會隱式類型轉換爲 int,當與 0xFF 按位與的時候,會將除了低 8 位的其他位全部置 0,這樣一來便將符號擴展的那些高位清除掉了。


最後附上一個自己寫的通用函數,用來將整型變量的二進制編碼輸出

/**
 * 將整型變量的二進制編碼形式輸出
 * @param n 整型變量
 * @param size 整型的二進制長度,可使用類似 Short.SIZE 獲得
 * @return 二進制編碼字符串
 */
public static String printBinary(long n, int size) {
	StringBuilder sb = new StringBuilder();
	for (int i = size - 1; i >= 0; i--) {
		sb.append(n >>> i & 0x01);
		if (i % 4 == 0) {
			sb.append(" ");
		}
	}
	return sb.toString();
}


發佈了54 篇原創文章 · 獲贊 101 · 訪問量 26萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章