InetAddress 是 Java 網絡 API 的地址抽象核心,封裝 IPv4/IPv6 地址與主機名解析。本文詳細講解:工廠方法創建實例、核心查詢方法、IPv4/IPv6 子類多態、實戰代碼範例、常見坑點。
InetAddress 無公共構造器,採用 工廠方法模式:靜態方法內部根據解析結果返回 Inet4Address 或 Inet6Address 實例,調用者無需關心具體子類型。
| 方法 | 參數 | 返回 | 用途 |
|---|---|---|---|
getByName(String host) | 主機名/域名/IP字串 | InetAddress | 單個地址解析 (最常用) |
getAllByName(String host) | 主機名/域名/IP字串 | InetAddress[] | 多 IP 解析 (負載均衡/容灾) |
getByAddress(byte[] addr) | 4字節(IPv4)或16字節(IPv6) | InetAddress | 從原始字節構建,無需 DNS |
getByAddress(String host, byte[] addr) | 主機名 + 原始字節 | InetAddress | 綁定主機名與指定 IP |
getLocalHost() | 無 | InetAddress | 獲取本機地址 (可能返回環回/站點本地) |
InetAddress ia = InetAddress.getByName("www.example.com");
System.out.println(ia.getCanonicalHostName()); // 標準主機名 (DNS PTR 記錄)
System.out.println(ia.getHostAddress()); // IP 字串 (如 93.184.216.34)
System.out.println(ia.getHostName()); // 主機名 (可能是傳入的 host)
System.out.println(ia.isLoopbackAddress()); // 是否環回地址 (127.0.0.1 / ::1)
System.out.println(ia.isAnyLocalAddress()); // 是否 0.0.0.0 / ::
System.out.println(ia.isLinkLocalAddress()); // 是否鏈路本地 (169.254.x.x / fe80::)
System.out.println(ia.isSiteLocalAddress()); // 是否站點本地 (私有網段,IPv6 已棄用)
System.out.println(ia.isMulticastAddress()); // 是否組播地址 (224.0.0.0/4 / ff00::/8)
System.out.println(ia.isMCGlobal()); // 是否全球組播
System.out.println(ia.isMCNodeLocal()); // 是否節點本地組播
System.out.println(ia.isMCLinkLocal()); // 是否鏈路本地組播
System.out.println(ia.isMCSiteLocal()); // 是否站點本地組播
System.out.println(ia.isMCOrgLocal()); // 是否組織本地組播
import java.net.*;
public class InetAddressDemo {
public static void main(String[] args) {
String host = args.length > 0 ? args[0] : "localhost";
try {
InetAddress[] addresses = InetAddress.getAllByName(host);
System.out.println("解析 " + host + " 共 " + addresses.length + " 個地址:");
for (int i = 0; i < addresses.length; i++) {
InetAddress ia = addresses[i];
System.out.printf(" [%d] %s (%s)%n",
i + 1, ia.getHostAddress(),
ia instanceof Inet4Address ? "IPv4" : "IPv6");
System.out.println(" Canonical: " + ia.getCanonicalHostName());
System.out.println(" Loopback: " + ia.isLoopbackAddress());
System.out.println(" Multicast: " + ia.isMulticastAddress());
}
} catch (UnknownHostException e) {
System.err.println("解析失敗: " + e.getMessage());
}
}
}
| 坑點 | 現象 | 解法 |
|---|---|---|
| getLocalHost() 返回 127.0.0.1 | /etc/hosts 把主機名映射到環回 | 檢查 /etc/hosts,確保主機名映射真實 LAN IP;或遍歷 NetworkInterface 獲取非環回地址 |
| DNS 解析緩存導致 IP 變更不生效 | JVM 緩存正/負解析結果 | 啟動參數 -Dsun.net.inetaddr.ttl=30 (正向 30s) -Dsun.net.inetaddr.negative.ttl=10 (負向 10s),0=永不緩存 |
| IPv6 環境下 getByName 返回 IPv6 優先 | 雙棧系統 IPv6 優先 | 若需強制 IPv4,用 Inet4Address.getByName() (需自行過濾) 或系統層面配置 |
| 安全管理器限制 | 非受信代碼調用 getByName 拋 SecurityException | 簽名 JAR / 配置 policy 文件授予 permission java.net.SocketPermission "*", "resolve" |
public static void printAllLocalAddresses() throws SocketException {
Enumeration interfaces = NetworkInterface.getNetworkInterfaces();
while (interfaces.hasMoreElements()) {
NetworkInterface ni = interfaces.nextElement();
if (!ni.isUp() || ni.isLoopback() || ni.isVirtual()) continue;
Enumeration addresses = ni.getInetAddresses();
while (addresses.hasMoreElements()) {
InetAddress ia = addresses.nextElement();
if (ia instanceof Inet4Address) {
System.out.println(ni.getName() + " → " + ia.getHostAddress());
}
}
}
}
InetAddress 是網絡編程的「身份證工廠」。掌握:工廠方法選擇 (單/多 IP)、核心查詢方法、DNS 緩存控制、本機網卡枚舉,即可靈活處理地址解析、服務發現、網絡診斷等場景。