前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java魔法之java.net.URL

Java魔法之java.net.URL

作者头像
青山师
发布2023-05-05 19:45:09
5230
发布2023-05-05 19:45:09
举报

Java魔法之java.net.URL【译】

最近发现一个很有意思的代码段:

代码语言:javascript
复制
HashSet set = new HashSet();
set.add(new URL("http://google.com"));
System.out.println(set.contains(new URL("http://google.com")));
Thread.sleep(60000);
System.out.println(set.contains(new URL("http://google.com")));

你猜想下,第3、5行会输出什么?

结果肯定不是truetrue

好了,大都数情况下结果可能为true, false

如果你关闭网络再运行得到的结果就可能为:truetrue了。

造成这种现象的原因就是java.net.URL 类的 hashCode()equals()方法的具体实现导致的。

我们来看看它的hashCode方法:

代码语言:javascript
复制
public synchronized int hashCode() {
    if (hashCode != -1)
        return hashCode;

    hashCode = handler.hashCode(this);
    return hashCode;
}


private int hashCode = -1;

我们可以看到hashCode是一个成员变量,只计算一次。

注意,java.net.URL 类是不可变的。

那么handler是啥玩意呢?是URLStreamHandler的一个子类,依赖于协议(file、http、ftp…)。

感兴趣的话可以查看下: java.net.URLStreamHandler#hashCode的逻辑。

我们看下URL.hashCode()的javadoc说明:

基于网址比较,是一个阻塞操作!

OMG!! 是一个阻塞操作呢!!

另一个刺激的是,handler会解析主机ip地址来计算哈希值。如果搞不定,则基于域名http://google.com计算哈希值。

如果ip是动态的,或者存在请求负载均衡,则主机的ip也是动态变化的——所以我们可能得到不同步的哈希值,这样在HashSet就是2各不同的实例的。

这样一点也不好,顺便说下,hashCode 和 equals 的性能很糟糕——因为URLStreamHandler会打开URLConnection。

那么如何避免这种情况发生呢?

  • 使用java.net.URI替换java.net.URL; 这不是最好的选择,但是也有了确定的哈希实现。
  • 不要在集合中使用java.net.URL,如果真要这么做,建议使用代表URL的String对象放到集合中。
  • 在你计算哈希值的时候,断网!!!——开玩笑啦。。。
  • 编写自己的URLStreamHandler子类实现合适的hashCode方法。

附录

参考:http://mishadoff.com/blog/java-magic-part-1-java-dot-net-dot-url/

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2023-05-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Java魔法之java.net.URL【译】
  • 附录
相关产品与服务
负载均衡
负载均衡(Cloud Load Balancer,CLB)提供安全快捷的流量分发服务,访问流量经由 CLB 可以自动分配到云中的多台后端服务器上,扩展系统的服务能力并消除单点故障。负载均衡支持亿级连接和千万级并发,可轻松应对大流量访问,满足业务需求。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档