两个 URI 对象相等但它们的 toString() 不相等
Two URI objects are equal but their toString() are not
我不明白为什么两个文件的 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()
结果。
不过,我只是好奇,在 class 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()
输出。
没有这样的约定,好像两个对象等于字符串表示需要相同。 Java equals
实现独立于 toString
方法。例如,以下 class 的实例都是相等的,但它们没有相同的 toString 表示形式。
public class Foo {
private String value;
@Override
public boolean equals(Object obj) {
return true;
}
@Override
public String toString() {
return "value";
}
}
在您的特定情况下,两个 URI
实例都相等,因为它们指向相同的路径,但字符串表示形式不同,因为其中一个包含冗余信息。在 toString
之前尝试使用 normalize 方法
URI#toString()
方法有据可查 here:
Returns the content of this URI as a string.
If this URI was created by invoking one of the constructors in this class then a string equivalent to the original input string, or to the string computed from the originally-given components, as appropriate, is returned. Otherwise this URI was created by normalization, resolution, or relativization, and so a string is constructed from this URI's components according to the rules specified in RFC 2396, section 5.2, step 7.
意思是,toString()
方法的结果取决于我们初始化 URI 对象的方式(总共 5 constructors。)
在这种情况下,您尝试以两种不同的方式初始化 2 个 URI 对象,因此 toString()
的结果是不同的。可以试试normalize()
方法。
看起来 equals 方法正在验证它们仅指向相同的 资源。但是,统一资源标识符字符串是不同的,因为它们以两种不同的方式访问同一资源。
这就像去商店用 1 美元钞票或 4 个 25 美分硬币购买 1 美元苏打水:您可以使用不同的方式获得相同的苏打水。收银台的工作人员说两种方式都可以,尽管他知道一张钞票和一堆硬币之间有明显的区别。
我不明白为什么两个文件的 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()
结果。
不过,我只是好奇,在 class 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()
输出。
没有这样的约定,好像两个对象等于字符串表示需要相同。 Java equals
实现独立于 toString
方法。例如,以下 class 的实例都是相等的,但它们没有相同的 toString 表示形式。
public class Foo {
private String value;
@Override
public boolean equals(Object obj) {
return true;
}
@Override
public String toString() {
return "value";
}
}
在您的特定情况下,两个 URI
实例都相等,因为它们指向相同的路径,但字符串表示形式不同,因为其中一个包含冗余信息。在 toString
URI#toString()
方法有据可查 here:
Returns the content of this URI as a string. If this URI was created by invoking one of the constructors in this class then a string equivalent to the original input string, or to the string computed from the originally-given components, as appropriate, is returned. Otherwise this URI was created by normalization, resolution, or relativization, and so a string is constructed from this URI's components according to the rules specified in RFC 2396, section 5.2, step 7.
意思是,toString()
方法的结果取决于我们初始化 URI 对象的方式(总共 5 constructors。)
在这种情况下,您尝试以两种不同的方式初始化 2 个 URI 对象,因此 toString()
的结果是不同的。可以试试normalize()
方法。
看起来 equals 方法正在验证它们仅指向相同的 资源。但是,统一资源标识符字符串是不同的,因为它们以两种不同的方式访问同一资源。
这就像去商店用 1 美元钞票或 4 个 25 美分硬币购买 1 美元苏打水:您可以使用不同的方式获得相同的苏打水。收银台的工作人员说两种方式都可以,尽管他知道一张钞票和一堆硬币之间有明显的区别。