【问题标题】:Two URI objects are equal but their toString() are not两个 URI 对象相等但它们的 toString() 不相等
【发布时间】:2018-09-22 14:19:57
【问题描述】:

我不明白为什么两个文件的 URIs 相等,但它们的 String 表示不相等。是bug吗?

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 类,这是一个好的实现吗:两个 URIs 是相等的,但具有不同的字符串表示。

在我的情况下,它是不同的,因为有不同的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

如您所见,如果我们从这两个URIs 中得到authority,那么在这两种情况下都是null

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

【问题讨论】:

  • 当我创建这些 URI 时,它们的字符串形式看起来和你的一样,但是它们都从各自的 getAuthority() 方法返回 null,无论是在 Java 8 还是 Java 9 中。所以,它们确实是相等。
  • @VGR 将您的评论添加为 UPDATE 2

标签: java file path java-8 uri


【解决方案1】:

URI#toString() 方法有据可查 here

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

意思是toString()方法的结果取决于我们初始化URI对象的方式(总共5 constructors。)

在这种情况下,您尝试以 2 种不同的方式初始化 2 个 URI 对象,因此 toString() 的结果是不同的。可以试试normalize()方法。

【讨论】:

  • 我明白了。但它不应该是这样的吧?令人困惑
【解决方案2】:

没有这样的契约,好像两个对象相等,字符串表示需要相同。 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 之前使用normalize 方法

【讨论】:

    【解决方案3】:

    看起来equals方法正在验证它们是否仅指向相同的资源。但是,Uniform Resource Identifier string of characters是不同的,因为它们以两种不同的方式访问同一个资源。

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

    【讨论】:

      猜你喜欢
      • 2021-04-19
      • 1970-01-01
      • 2014-01-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多