如何识别已被不恰当地拒绝的Java URI hashCode()错误

Gar*_*son 12 java uri equals hashcode

Java Object契约的一个基本部分是该hashCode()方法应该与该equals()方法一致.这是有道理的并且易于理解:如果两个对象在某种程度上"相等",则它们应该返回相同的哈希码.如果没有,你可以将一个对象放在一个HashSet,例如,然后检查一个单独的实例是否在集合中并错误地返回false,即使该equals()方法会认为对象是等价的.

事实上,从Java 6开始,Java的URI代码就存在这个问题.试试这段代码:

import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;

import java.net.URI;

import org.junit.Test;

public class URITest
{

    @Test
    public void testURIHashCode()
    {
        final URI uri1 = URI.create("http://www.example.com/foo%2Abar");
        final URI uri2 = URI.create("http://www.example.com/foo%2abar");
        assertThat("URIs are not equal.", uri1, equalTo(uri2));
        assertThat("Equal URIs do not have same hash code.", uri1.hashCode(), equalTo(uri2.hashCode()));
    }
}
Run Code Online (Sandbox Code Playgroud)

根据RFC 3968,URI转义序列不区分大小写; 也就是说,%2A%2a被认为是等同的.Java URI.equals()实现将此考虑在内.但是,URI.hashCode()实施并没有考虑到这一点!这意味着,返回两个URI的实例trueURI.equals()但可以返回不同的散列码,如在示出的代码以上!

我提交了这个问题,据说导致了Java Bug 7134993,但该bug已不再可用.但是,Java Bug 7054089中显示了同样的问题.(我不确定这是来自我的提交还是来自其他人,但问题是相同的.)然而,该错误被评估拒绝,"引用的示例是不透明的URI,因此特定于方案的部分不是解析".

评估此错误的人必须不熟悉它的含义equals()hashCode()保持一致.Object.equals()明确规定的合同,"如果两个对象根据equals(Object)方法相等,那么在两个对象中的每一个上调用hashCode方法必须产生相同的整数结果." 注意使用"必须"而不是"应该".

这里的要点是,即使评估者声称URI是"不透明的"和"未解析的",URI.equals()实现(与他/她的主张相反)确实解析了URI并允许不区分大小写.该URI.hashCode()执行不.

所以我在这里完全密集并且遗漏了一些明显的东西吗?如果我是,有人请告诉我我的错误,我会将你的答案标记为正确.否则,问题是:现在Sun/Oracle似乎不再允许对提交的错误进行评论,我有什么办法可以获得对互联网主要标识符的Java实现中的这个基本问题的认可和行动,即URI?

Gar*_*son 2

好消息!Oracle 似乎已经在J​​DK-7171415中修复了 Java 8 的这个错误!我已经验证我的上述测试现在在 Windows 10 Pro 64 位上的 Java 1.8.0_92 中通过。新的错误单没有引用任何以前的错误单,所以我不知道它是如何发生的。但我很高兴他们终于修好了。