Переопределение методов класса Object в интерфейсе как дефолтных методов вполне бессмысленно, так как такие методы всё равно будут недостижимые (unreachable).
Дело в том, что реализация метода в классе всегда имеет высший приоритет по сравнению с дефолтной реализацией в интерфейсе, даже если эта реализация выполнена в классе Object.
Поэтому и возникает ошибка компиляции Default method 'equals' overrides a member of 'java.lang.Object' при попытке переопределить метод с сигнатурой public boolean equals(Object o):
interface Foo {
int foo();
@Override
default boolean equals(Object o) { // ошибка компиляции
return false;
}
}
А определение метода boolean equals(Foo f) в интерфейсе не является переопределением соответствующего метода, о чём указано в комментариях (аннотация @Override не может применяться).
Выход заключается только в использовании абстрактного класса, но для корректной фильтрации при помощи distinct потребуется также переопределить метод hashCode:
interface GoodFoo {
int foo();
}
abstract class FooImpl implements GoodFoo {
@Override
public boolean equals(Object o) {
if (this == o) return true;
return o instanceof GoodFoo && this.foo() == ((GoodFoo) o).foo();
}
@Override
public int hashCode() {
return foo();
}
}
Тест:
List<GoodFoo> foos = Arrays.asList(
new FooImpl() {
@Override public int foo() { return 1; }
},
new FooImpl() {
@Override public int foo() { return 2; }
},
new FooImpl() {
@Override public int foo() { return 1; }
}
);
foos.stream()
.distinct()
.mapToInt(GoodFoo::foo)
.forEach(System.out::println);
Вывод:
1
2
Связанный вопрос на основном SO: Java8: Why is it forbidden to define a default method for a method from java.lang.Object
equals(), а определили свой – Byb Jan 09 '24 at 11:30