Я не понимаю, почему два файла 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/./
Я понимаю, что технически вы можете полностью реализовать реализацию, в которой два объекта равны на основе метода equals, но имеют другой результат toString().
Однако мне просто любопытно, в случае класса URI, это хорошая реализация: два URI равны, но с разным строковым представлением.
В моем случае это другое, потому что есть разные результаты getAuthority(). Но тогда почему они равны? Это сбивает с толку. Если я не распечатал результат и не проверил его исходный код, я не узнаю об этом.
Согласно комментарию @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
Как видите, если мы получаем authority от обоих этих двух URI, то в обоих случаях это null.
Однако у них нет того же выхода toString().
@VGR добавил ваш комментарий как ОБНОВЛЕНИЕ 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
Метод URI#toString() хорошо документирован здесь:
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 конструкторов.)
В этом случае вы пытаетесь инициализировать 2 объекта URI двумя разными способами, поэтому результаты toString() будут разными. Можете попробовать метод normalize().
Я понимаю. Но так не должно быть, правда? Это сбивает с толку
Похоже, что метод equals проверяет, что они указывают только на один и тот же ресурс. Однако Строка символов унифицированного идентификатора ресурса отличается, потому что они обращаются к одному и тому же ресурсу двумя разными способами.
Это все равно, что пойти в магазин и купить газировку за 1 доллар на 1 доллар или 4 четвертных монеты: вы получите доступ к одной и той же газировке, используя разные способы ее приобретения. Парень у кассы говорит, что заплатить в любом случае было бы одинаково хорошо, хотя он знает, что есть явная разница между купюрой и кучей монет.
Когда я создал эти URI, их строковые формы выглядели так же, как ваша, но оба они вернули null из своих соответствующих методов
getAuthority(), как в Java 8, так и в Java 9. Итак, они действительно равны.