InetAddress 是 Java 网络编程中一个非常核心和基础的类,它不对应任何具体的网络协议,而是用于表示 IP 地址(无论是 IPv4 还是 IPv6),你可以把它想象成一个“网络地址的抽象表示”。

InetAddress 的核心概念
InetAddress 主要封装了两个关键信息:
- 主机名:
www.google.com或localhost。 - IP 地址:
217.160.142(IPv4) 或2607:f8b0:4006:805::200e(IPv6)。
它不包含端口号,端口号由另一个类 java.net.InetSocketAddress 来处理。
InetAddress 是一个抽象类,我们通常不直接使用 new 来创建它的实例,而是通过它提供的静态工厂方法来获取。
如何获取 InetAddress 实例?
主要有以下几种静态方法:

1 根据主机名获取
这是最常见的用法,通过一个易于记忆的主机名来获取其 IP 地址信息。
getByName(String host): 最常用的方法,它可以根据主机名获取InetAddress实例,如果主机名无法解析,会抛出UnknownHostException异常。getAllByName(String host): 如果主机名对应多个 IP 地址(为了负载均衡或冗余),此方法会返回一个InetAddress数组。
示例代码:
import java.net.InetAddress;
import java.net.UnknownHostException;
public class GetByNameExample {
public static void main(String[] args) {
String host = "www.baidu.com";
try {
// 获取单个 InetAddress
InetAddress address = InetAddress.getByName(host);
System.out.println("主机名: " + address.getHostName());
System.out.println("IP 地址: " + address.getHostAddress());
System.out.println("完整地址字符串: " + address.toString());
System.out.println("------------------------------------");
// 获取所有 InetAddress
InetAddress[] allAddresses = InetAddress.getAllByName(host);
System.out.println(host + " 的所有 IP 地址:");
for (InetAddress addr : allAddresses) {
System.out.println(" - " + addr.getHostAddress());
}
} catch (UnknownHostException e) {
System.err.println("无法找到主机: " + host);
e.printStackTrace();
}
}
}
输出可能类似于:
主机名: www.baidu.com
IP 地址: 182.61.200.7
完整地址字符串: www.baidu.com/182.61.200.7
------------------------------------
www.baidu.com 的所有 IP 地址:
- 182.61.200.7
- 182.61.200.6
- 182.61.200.5
2 根据IP地址获取
如果你已经知道 IP 地址,也可以通过它来获取 InetAddress 实例。

getByAddress(byte[] addr): 通过一个字节数组(IPv4 是 4 字节,IPv6 是 16 字节)来创建InetAddress实例。getByAddress(String host, byte[] addr): 通过主机名和字节数组来创建,可以同时指定两者。
示例代码:
import java.net.InetAddress;
import java.net.UnknownHostException;
public class GetByAddressExample {
public static void main(String[] args) {
try {
// 通过 IPv4 地址的字节数组创建
byte[] ipv4Address = { (byte) 8, 8, 8, 8 }; // Google DNS
InetAddress address = InetAddress.getByAddress(ipv4Address);
System.out.println("IP 地址: " + address.getHostAddress());
System.out.println("主机名: " + address.getHostName()); // 可能返回 IP 本身,如果无法反向解析
System.out.println("------------------------------------");
// 通过主机名和 IP 地址创建
byte[] ipv4Address2 = { (byte) 114, 114, 114, 114 }; // 114 DNS
InetAddress address2 = InetAddress.getByAddress("dns114", ipv4Address2);
System.out.println("指定主机名: " + address2.getHostName());
System.out.println("IP 地址: " + address2.getHostAddress());
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
}
3 获取本地地址
getLocalHost(): 获取本地主机的InetAddress实例,它尝试解析本地机器的主机名,如果解析失败,通常会返回一个以0.0.1(IPv4) 或:1(IPv6) 为地址的InetAddress。
示例代码:
import java.net.InetAddress;
import java.net.UnknownHostException;
public class GetLocalHostExample {
public static void main(String[] args) {
try {
InetAddress localHost = InetAddress.getLocalHost();
System.out.println("本地主机名: " + localHost.getHostName());
System.out.println("本地IP地址: " + localHost.getHostAddress());
} catch (UnknownHostException e) {
System.err.println("无法获取本地主机信息。");
e.printStackTrace();
}
}
}
InetAddress 的常用方法
获取到 InetAddress 实例后,你可以调用以下方法来获取信息:
| 方法 | 描述 |
|---|---|
getHostName() |
获取此 IP 地址的主机名,如果无法通过反向 DNS 解析,可能会返回 IP 地址本身。 |
getHostAddress() |
返回 IP 地址的字符串表示。"192.168.1.1" 或 "2001:db8::1"。 |
getAddress() |
返回 IP 地址的原始字节数组形式。 |
toString() |
返回主机名和 IP 地址的字符串,格式为 hostname/address。 |
isLoopbackAddress() |
判断 IP 地址是否是环回地址,IPv4 是 0.0.1,IPv6 是 :1。 |
isAnyLocalAddress() |
判断 IP 地址是否是“通配符”地址,IPv4 是 0.0.0,IPv6 是 。 |
isLinkLocalAddress() |
判断是否是链路本地地址(IPv6 的 fe80::/10)。 |
isSiteLocalAddress() |
判断是否是站点本地地址(IPv6 的 fec0::/10,已废弃,但仍有实现)。 |
isMCGlobal() |
判断是否是全球组播地址。 |
isMCLinkLocal() |
判断是否是链路本地组播地址。 |
isMCSiteLocal() |
判断是否是站点本地组播地址。 |
isMulticastAddress() |
判断是否是组播地址。 |
isReachable(int timeout) |
网络探测:尝试判断此地址是否可以到达,它会尝试建立一个 ICMP (ping) 请求或 TCP 连接。timeout 是超时时间(毫秒)。注意:此操作可能耗时且不总是可靠,因为它可能被防火墙阻止。 |
示例代码(使用 isReachable):
import java.net.InetAddress;
import java.net.UnknownHostException;
public class ReachableExample {
public static void main(String[] args) {
String host = "www.google.com";
try {
InetAddress address = InetAddress.getByName(host);
System.out.println("正在尝试连接到 " + address.getHostAddress() + "...");
// 设置超时时间为 5000 毫秒 (5秒)
boolean isReachable = address.isReachable(5000);
if (isReachable) {
System.out.println("主机 " + host + " 可以到达。");
} else {
System.out.println("主机 " + host + " 无法到达。");
}
} catch (UnknownHostException e) {
System.err.println("未知主机: " + host);
} catch (Exception e) {
System.err.println("连接测试时发生错误: " + e.getMessage());
}
}
}
IPv4 vs. IPv6
InetAddress 类天然支持 IPv4 和 IPv6,具体使用哪种,取决于以下几个因素:
- 操作系统和 JVM 配置:现代操作系统和 JVM 默认都支持 IPv6。
- DNS 解析结果:DNS 服务器返回的记录决定了
getByName返回的是Inet4Address还是Inet6Address。 java.net系统属性:你可以通过 JVM 参数来控制网络栈的行为。
相关的系统属性:
| 属性名 | 描述 | 默认值 |
|---|---|---|
java.net.preferIPv4Stack |
如果设置为 true,则禁用 IPv6,只使用 IPv4。 |
false |
java.net.preferIPv6Addresses |
如果设置为 true,在主机名解析时,优先返回 IPv6 地址,如果为 false,则优先返回 IPv4 地址。 |
false |
示例: 在运行程序时,强制使用 IPv4 栈:
java -Djava.net.preferIPv4Stack=true YourClassName
最佳实践和注意事项
- 总是处理异常:所有涉及主机名解析的方法都可能抛出
UnknownHostException,务必使用try-catch块处理。 - 不要阻塞主线程:
getByName和isReachable都是网络 I/O 操作,可能会阻塞较长时间,在 GUI 应用或高并发服务器中,应在后台线程(如ExecutorService)中执行这些操作。 isReachable的局限性:不要过度依赖isReachable的结果,防火墙、NAT 设备、主机配置等都可能导致false的误报,对于关键的网络连通性检查,最好尝试建立你自己的 TCP 连接(连接到目标主机的 80 端口)。- 缓存结果:DNS 解析是一个相对昂贵的操作,如果你的应用需要频繁地查询同一个主机名,考虑将解析结果缓存起来,以减少网络开销和延迟。
- 理解
getHostName():调用getHostName()可能会触发一次反向 DNS 查询,这同样是一个网络操作,也可能耗时,如果你只需要 IP 地址,直接使用getHostAddress()更高效。
InetAddress 是 Java 网络编程的基石,它将复杂的 IP 地址和主机名概念封装成了一个易于使用的对象,掌握如何创建、获取和使用 InetAddress 实例,是学习更高级网络知识(如 Socket 编程、HTTP 请求等)的必备前提,记住它的核心功能——地址解析,并注意其可能带来的网络 I/O 阻塞和异常问题。
