首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java InetAddress 獲取 IP 地址 byte 數組負數問題解析與修正

     編輯:Java 相關知識

使用 InetAddress.getAddress() 獲取 IP 地址時,返回 byte[] 數組。直接打印會發現部分段落顯示為負數(如 61.135.169.105 變為 61.-121.-87.105),這是 Java 無無符號類型導致的經典陷阱。本文深度解析原理並提供通用修正方案。

一、現象重現

InetAddress addr = InetAddress.getByName("61.135.169.105");
byte[] bytes = addr.getAddress();
// 直接打印 bytes[1] → -121
// 直接打印 bytes[2] → -87

二、根因深度剖析

1. Java 無 unsigned 類型

  • byte:8 位,有符號,範圍 -128 ~ 127
  • IP 段:8 位,無符號,範圍 0 ~ 255

2. 補碼表示導致的「負數」

以 135 為例:

  • 二進制:1000 0111(最高位為 1)
  • Java 視為 byte 有符號數 → 符號位 = 1 → 負數
  • 補碼轉原碼:1000 0111 → 取反+1 → 1111 1001 → 十進制 -121
  • 驗證:135 + 121 = 256(模 256 同餘)

以 65 為例:

  • 二進制:0100 0001(最高位 0)
  • 正數,補碼即原碼 → 65,顯示正常

三、修正方案:& 0xFF 位運算

將 byte 提升為 int,與 0xFF(二進制 24 個 0 + 8 個 1)按位與,清除符號擴展位,保留低 8 位真實值。

public static String formatIp(byte[] bytes) {
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < bytes.length; i++) {
        // 關鍵:byte 自動提升為 int,& 0xFF 保留低 8 位
        int unsignedByte = bytes[i] & 0xFF;
        sb.append(unsignedByte);
        if (i < bytes.length - 1) sb.append(".");
    }
    return sb.toString();
}

// 測試
byte[] ipBytes = {(byte) 135, (byte) 169};
System.out.println(formatIp(ipBytes));  // 輸出: 135.169

四、通用工具方法:整數二進制可視化

輔助調試位運算、理解補碼表示:

/**
 * 打印整數二進制表示
 * @param n 目標數值
 * @param size 位寬度(如 Byte.SIZE=8, Integer.SIZE=32)
 * @return 格式化二進制字符串(每 4 位分組)
 */
public static String printBinary(long n, int size) {
    StringBuilder sb = new StringBuilder();
    for (int i = size - 1; i >= 0; i--) {
        // 無符號右移 >>> 關鍵:補 0,避免負數符號擴展
        sb.append((n >>> i) & 0x01);
        if (i % 4 == 0) sb.append(" ");
    }
    return sb.toString();
}

// 使用示例
System.out.println(printBinary(135, Byte.SIZE));   // 1000 0111
System.out.println(printBinary(-121, Byte.SIZE));  // 1000 0111 (相同位模式)
System.out.println(printBinary(135 & 0xFF, Byte.SIZE)); // 0000 0000 ... 1000 0111 (int 32位)

五、最佳實踐總結

  1. 獲取 IP 字符串首選:InetAddress.getHostAddress() 直接返回標準點分十進制字符串,無需手動解析
  2. 必須處理 byte[] 時:統一使用 b & 0xFF 轉無符號值
  3. 網絡編程中:ByteBuffer、DataOutputStream 寫入 byte 時無需轉換,網絡傳輸本質是無符號字節流
  4. 理解補碼、有符號/無符號、位運算:是處理網絡協議、二進制協議、加密算法的基本功

Java 設計哲學「簡單性」犧牲了無符號類型,開發者需自行處理無符號語義。掌握 & 0xFF 慣用語,是 Java 程序員處理二進制數據的必備技能。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved