千万别用URL.equals【痛苦面具.gif】

今天看到个有趣的代码,被这套操作震惊😱了一下午.

请听题

Java.net.URL对象,进行equals比较,会发生什么?

题目

URL url = new URL("http://afk.now.sh");
URL url3 = new URL("http://carbon.now.sh");
System.out.println(url.equals(url3));

答案(白色的)

DNS 查询, 他会加锁解析DNS,然后比较指向的ip是否一致.

true

😱

这玩意直接把我看懵了.

然后,就去看了URLequals方法实现.

然后,我就更懵😳了.

千万别用URL.equals【痛苦面具.gif】

URL.equals

public boolean equals(Object obj) {
    if (!(obj instanceof URL u2))
        return false;

    return handler.equals(this, u2);
}

源码是这样, 他借助了一个URLStreamHandlersameFile方法来判断逻辑的.

sameFile

protected boolean sameFile(URL u1, URL u2) {
    // Compare the protocols.
    if (!((u1.getProtocol() == u2.getProtocol()) ||
          (u1.getProtocol() != null &&
           u1.getProtocol().equalsIgnoreCase(u2.getProtocol()))))
        return false;

    // Compare the files.
    if (!(u1.getFile() == u2.getFile() ||
          (u1.getFile() != null && u1.getFile().equals(u2.getFile()))))
        return false;

    // Compare the ports.
    int port1, port2;
    port1 = (u1.getPort() != -1) ? u1.getPort() : u1.handler.getDefaultPort();
    port2 = (u2.getPort() != -1) ? u2.getPort() : u2.handler.getDefaultPort();
    if (port1 != port2)
        return false;

    // Compare the hosts.
    if (!hostsEqual(u1, u2))
        return false;

    return true;
}

很长, 不过整体是分4步:

  1. 比较协议
  2. 比较文件
  3. 比较port
  4. 比较host

hostsEqual

最后一步这个hostEqual就是真的让人跌掉下巴了.代码是这样的.

protected boolean hostsEqual(URL u1, URL u2) {
    InetAddress a1 = getHostAddress(u1);
    InetAddress a2 = getHostAddress(u2);
    // if we have internet address for both, compare them
    if (a1 != null && a2 != null) {
        return a1.equals(a2);
    // elseif both have host names, compare them
    } else if (u1.getHost() != null && u2.getHost() != null)
        return u1.getHost().equalsIgnoreCase(u2.getHost());
     else
        return u1.getHost() == null && u2.getHost() == null;
}

关键点在开头的getHostAddress

synchronized InetAddress getHostAddress() {
    if (hostAddress != null) {
        return hostAddress;
    }

    if (host == null || host.isEmpty()) {
        return null;
    }
    try {
        hostAddress = InetAddress.getByName(host);
    } catch (UnknownHostException | SecurityException ex) {
        return null;
    }
    return hostAddress;
}

他会调用两次DNS解析, 检查一下,获取ip地址….. 而且这方法还是带锁的…

千万别用URL.equals【痛苦面具.gif】
痛苦

神奇的上古代码

代码Java1.3里出现的, 也就是1999年,23多年前的代码了. 要是个男孩子都够结婚年龄,是个女孩子都已经是2个孩子的妈了.

这是给当年的情景准备的,现代互联网,多个域名指向同一个ip的场景很常见, 这个写法基本上算是一点用都没有.

然而,为了兼容性还留着.😯

经验&教训

URLequals方法的人确实不多, 不是什么常规操作.

不过万一某一天, 谁手贱把这东西给用到HashMap或者HashSet之类的地方,再或者给了stream操作…那就等坑吧.

项目里如果有什么静态扫描工具的话, 该用上就用上,可以以防万一.

除了这个坑爹的URL.equals,还有Stack,HashTable,这一类的上古集合类,发现用就直接报警.早发现早治疗.

当然, 还有一个一定要记得的事,千万不要不看文档瞎写.很多类, 平时用的很多,但是如果没看过文档, 他们的某些方法,就是最熟悉的陌生人,坑死人不偿命.

千万别用URL.equals【痛苦面具.gif】



五一劳动节就要到了, 祝大家五一节快乐,高速免费🆓快乐.

原文始发于微信公众号(K字的研究):千万别用URL.equals【痛苦面具.gif】

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/24762.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!