以下代码可以获取到192.168.1.3对应的主机:
InetAddress ia = InetAddress.getByAddress(new byte[] { (byte) 192,(byte) 168, 1, 3 });
参数接收的是一个byte数组,我们都知道,byte数组的范围是-128~127,那么以上代码强转成byte为什么不会溢出,还可以正确获取到对应的主机呢?
以下是getByAddress方法的源码:
public static InetAddress getByAddress(byte[] addr) throws UnknownHostException {
return getByAddress(null, addr);
}
public static InetAddress getByAddress(String host, byte[] addr) throws UnknownHostException {
return getByAddress(host, addr, -1 /* scopeId */);
}
// Do not delete. Called from native code.
private static InetAddress getByAddress(String host, byte[] addr, int scopeId) throws UnknownHostException {
if (host != null && host.length() > 0 && host.charAt(0) == '[') {
if (host.charAt(host.length()-1) == ']') {
host = host.substring(1, host.length() -1);
}
}
if (addr != null) {
if (addr.length == Inet4Address.INADDRSZ) {
//IPv4是长度为4个字节的byte数组
return new Inet4Address(host, addr);
} else if (addr.length == Inet6Address.INADDRSZ) {
//IPv6是长度为16个字节的byte数组
byte[] newAddr = IPAddressUtil.convertFromIPv4MappedAddress(addr);
if (newAddr != null) {
return new Inet4Address(host, newAddr);
} else {
return new Inet6Address(host, addr, scopeId);
}
}
}
throw new UnknownHostException("addr is of illegal length");
}
以IPv4为例,以上代码返回了:
return new Inet4Address(host, addr);
Inet4Address(String hostName, byte addr[]) {
holder().hostName = hostName;
holder().family = AF_INET;
if (addr != null) {
//看到这里就应该都明白了,底层用的是位运算,将4个字节直接按位运算转成了int类型,所以不存在溢出一说
if (addr.length == INADDRSZ) {
int address = addr[3] & 0xFF;
address |= ((addr[2] << 8) & 0xFF00);
address |= ((addr[1] << 16) & 0xFF0000);
address |= ((addr[0] << 24) & 0xFF000000);
holder().address = address;
}
}
}
到这里我们可能还存有一个疑问,IP的最高8位也可能是11111111,那最后拼接起来的int类型IP值是不是也会溢出呢?
我们通过getHostAdress方法获取到的IP地址却是正常的:
public String getHostAddress() {
return numericToTextFormat(getAddress());
}
先看看getAdress()是怎么写的:
public byte[] getAddress() {
int address = holder().getAddress();
byte[] addr = new byte[INADDRSZ];
addr[0] = (byte) ((address >>> 24) & 0xFF);
addr[1] = (byte) ((address >>> 16) & 0xFF);
addr[2] = (byte) ((address >>> 8) & 0xFF);
addr[3] = (byte) (address & 0xFF);
return addr;
}
可以看出他是将int类型IP地址按照位运算转成了byte数组(java的API底层位运算是很常见的,提高了代码的执行效率)
static String numericToTextFormat(byte[] src) {
return (src[0] & 0xff) + "." + (src[1] & 0xff) + "." + (src[2] & 0xff) + "." + (src[3] & 0xff);
}
最终是用到了以上numericToTextFormat(byte[] src)这个静态方法,仍然是位运算,只不过这里位运算之后自动提升为了int类型,所以即便是位运算之后结果是11111111,也不会溢出。