/** Long → x.x.x.x */
public static String longToIp(long ip) {
return ((ip >>> 24) & 0xFF) + "." +
((ip >>> 16) & 0xFF) + "." +
((ip >>> 8) & 0xFF) + "." +
(ip & 0xFF);
}
/** x.x.x.x → Long */
public static long ipToLong(String ip) {
long result = 0;
for (String seg : ip.split("\\.")) {
result = (result << 8) + Long.parseLong(seg);
}
return result;
}
使用無符號右移 >>>> 與位運算,效能遠超字符串拼接。
private static final Map MASK_CACHE = new HashMap<>();
static {
for (int i = 1; i <= 32; i++) {
long mask = i == 32 ? 0xFFFFFFFFL : (0xFFFFFFFFL << (32 - i));
MASK_CACHE.put(i, longToIp(mask));
}
}
public static String bitToMask(int bits) {
return MASK_CACHE.getOrDefault(bits, "0.0.0.0");
}
public static int maskToBit(String mask) {
return ipToLong(mask) == 0 ? 0 : Long.bitCount(ipToLong(mask));
}
靜態緩存 32 條映射,O(1) 查詢;Long.bitCount 一行搞定反向解析。
/** 返回網段起始 IP (Long) */
public static long networkStart(String ip, int maskBits) {
return ipToLong(ip) & ipToLong(bitToMask(maskBits));
}
/** 返回網段結束 IP (Long) */
public static long networkEnd(String ip, int maskBits) {
long start = networkStart(ip, maskBits);
long hostBits = ~ipToLong(bitToMask(maskBits)) & 0xFFFFFFFFL;
return start | hostBits;
}
/** 可用主機數 = 2^(32-mask) - 2 */
public static long usableHosts(int maskBits) {
if (maskBits <= 0 || maskBits >= 32) return 0;
return (1L << (32 - maskBits)) - 2;
}
@Test
public void testCidr() {
String ip = "218.240.38.69";
int mask = 30; // 255.255.255.252
assertEquals("218.240.38.68", longToIp(networkStart(ip, mask)));
assertEquals("218.240.38.71", longToIp(networkEnd(ip, mask)));
assertEquals(2, usableHosts(mask)); // 僅 .69 .70 可用
}
java.net.InetAddress 或第三方庫 避免手寫解析 BugInet6Address + 128 位 BigIntegercom.google.guava:guava 的 InetAddresses 或 ipaddress 庫public final class IpUtils {
private IpUtils() {} // 工具類禁止實例化
// 上述所有 static 方法
// ...
}
一個精心設計的 IpUtils,能讓網絡相關業務代碼乾淨如新。