Java Object
契约的一个基本部分是 hashCode()
方法应该与 equals()
方法一致。这是有道理的,也很容易理解:如果两个对象在某种程度上“相等”,它们应该返回相同的哈希码。如果不是,您可以将一个对象放入 HashSet
中,例如,然后检查集合中是否有一个单独的实例并错误地返回 false
,甚至尽管 equals()
方法会认为对象是等价的。
事实上 Java 的 URI 代码从 Java 6 开始就有这个问题。试试这个代码:
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()));
}
}
根据 RFC 3968,URI 转义序列不区分大小写;也就是说,%2A
和 %2a
被认为是等价的。 Java URI.equals()
实现考虑了这一点。但是,URI.hashCode()
实现没有考虑到这一点!这意味着为 URI.equals()
返回 true
的两个 URI 实例仍然可以返回不同的哈希码,如上面的代码所示!
我提交了这个问题,据推测它会导致 Java 错误 7134993,但该错误不再可用。不过,Java Bug 7054089 中显示了同样的问题。 . (我不确定这是我提交的还是其他人提交的,但问题是一样的。)但是,评估拒绝了该错误,“引用的示例是不透明的 URI,因此方案特定部分未被解析。”
评估此错误的人一定不熟悉 equals()
和 hashCode()
保持一致意味着什么。 Object.equals()
的约定明确指出,“如果根据 equals(Object) 方法两个对象相等,则对这两个对象中的每一个调用 hashCode 方法必须产生相同的整数结果”请注意使用“必须”,而不是“应该”。
这里的要点是,即使评估者声称 URI 是“不透明的”和“未解析的”,URI.equals()
实现(与他/她的说法相反)是实际上是解析 URI 并允许不区分大小写。 URI.hashCode()
实现不是。
所以我是不是在这里完全密集而遗漏了一些明显的东西?如果是,请有人告诉我我的错误,我会将您的回答标记为正确。否则,问题是:既然 Sun/Oracle 似乎不再允许对已提交的错误发表评论,那么在 Internet 的主要标识符 URI 的 Java 实现中,我有什么办法来获得对这个基本问题的认可和采取行动?
最佳答案
我会使用您在此处提供的示例而不是错误 7054089 中的示例重新提交针对 Java 1.7.0_17 的错误。我检查过您的 StackOverflow 示例也适用于该版本。我听说 Oracle 已经关闭了 Java 6 上除安全问题之外的错误修复。
在您提交的原始错误中,您提供的 URI 是不透明的 URI,这可能会让评估者失望。我认为你的意思是 RFC 2396。
此外,您可能会得到一个新的评估者:)
在我看来,他们在这里肯定违反了 hashCode() 的约定。
很遗憾他们没有像 StackOverflow 这样的 Java 注释机制(或者像过去那样的基本注释。)
关于java - 如何识别已被不当拒绝的 Java URI hashCode() 错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16257996/