两个 URI 对象相等,但它们的 toString() 不相等



我不明白为什么两个文件的URI相等,但它们的String表示不相等。这是一个错误吗?

assertEquals(new File(".").toURI(), Paths.get(".").toUri()); // pass
assertEquals(new File(".").toURI().toString(), Paths.get(".").toUri().toString()); // fail
// org.opentest4j.AssertionFailedError: 
// Expected :file:/path/to/the/directory/./
// Actual   :file:///path/to/the/directory/./

更新 1

我知道,从技术上讲,您可以完全实现,其中两个对象基于equals方法相等,但具有不同的toString()结果。

但是,我只是好奇,在类 URI 的情况下,它是否是一个很好的实现:两个URI相等但具有不同的字符串表示形式。

就我而言,这是不同的,因为有不同的getAuthority()结果。但是,为什么它们是平等的呢?这是令人困惑的。如果我没有打印出结果并检查它的源代码,我就不会意识到这一点。

更新 2

根据@VGR下面的评论,我做了另一个测试如下:

    System.out.println(new File(".").toURI()); // file:/path/to/the/directory/./
    System.out.println(Paths.get(".").toUri()); // file:///path/to/the/directory/./
    System.out.println(new File(".").toURI().getAuthority()); // null
    System.out.println(Paths.get(".").toUri().getAuthority()); // null

如您所见,如果我们从这两个URI中得到authority,则在这两种情况下都是null的。

但是,它们没有相同的toString()输出。

URI#toString()方法在这里有很好的文档:

以字符串形式返回此 URI 的内容。 如果此 URI 是通过调用此类中的一个构造函数创建的,则返回与原始输入字符串等效的字符串,或与从原始给定组件计算的字符串(视情况而定(等效。否则,此 URI 是通过规范化、解析或相对化创建的,因此将根据 RFC 2396 第 5.2 节步骤 7 中指定的规则从此 URI 的组件构造字符串。

这意味着,toString()方法的结果取决于我们初始化 URI 对象的方式(总共 5 个构造函数(。

在本例中,您尝试以 2 种不同的方式初始化 2 个 URI 对象,以便toString()的结果不同。可以尝试normalize()方法。

没有这样的契约,如果两个对象相等,字符串表示需要相同。Java equals实现独立于toString方法。例如,以下类的实例都是相等的,但它们没有相同的toString表示形式。

public class Foo {
    private String value;
    @Override
    public boolean equals(Object obj) {
        return true;
    }
    @Override
    public String toString() {
        return "value";
    }
}

在您的特定情况下,两个实例URI是相等的,因为它们指向相同的路径,但字符串表示形式不同,因为它们之一包含冗余信息。尝试在 toString 之前使用规范化方法

看起来 equals 方法正在验证它们是否仅指向同一资源。但是,统一资源标识符字符串是不同的,因为它们以两种不同的方式访问同一资源。

这就像去一家商店用 1 美元的钞票或 4 个季度的硬币购买 1 美元的苏打水:您将使用不同的方式获得相同的苏打水。收银台的人说,无论哪种方式付款都同样好,尽管他知道钞票和一堆硬币之间有明显的区别。

相关内容

  • 没有找到相关文章

最新更新