Почему на super метод records нельзя сослаться
Почему на суперметоды record
нельзя сослаться?
Допустим у меня есть класс:
public record Test(String str1,String str2) {
@Override //Не выдает ошибку
public String str1() {
return super.str1(); //Cannot resolve method 'str1' in 'Record'
}
}
На момент написания его конечно нет, но при этом:
public static void main(String[] args) {
Test test = new Test("строка1","строка2");
String str1 = test.str1();
String str2 = test.str2(); //Оба работают корректно
}
test.str2()
, test.str2()
и @Override
работают корректно то-есть находят его, но при super.str1()
выдается ошибка Cannot resolve method 'str1' in 'Record'
Ответы (1 шт):
Почему на суперметоды record
нельзя сослаться?
Коротко, "потому что их нет"(с) Майор Пейн.
Кортежи record
представляют собой финальные неизменяемые классы-обёртки (data class) для хранения и передачи данных, чтобы заменить привычные POJO классы (бины).
Фактически они неявно наследуются от абстрактного класса java.lang.Record
, в котором, разумеется, не определены геттеры для компонентов кортежа.
В данном случае имеет место попытка вызвать геттер, отсутствующий в классе-предке, обращаясь к нему при помощи super
, о чём и сообщает компилятор.
Более того, у кортежей не определены даже стандартные методы класса Object
: equals
, hashCode
, toString
-- все они являются абстрактными! Таким образом, для кортежа нельзя также написать что-то вроде super.hashCode()
или super.toString().
Кроме того, такое переопределение геттера само по себе не слишком хорошо и его можно считать дурнопахнущим кодом (code smell)), так как есть риск прочитать значение, которое отличается от записанного значения, что также сломает контракт Record::equals
.
@Override //Не выдает ошибку
Дело в том, что сама аннотация @Override
была модифицирована для геттеров в кортежах, для чего была изменено её описание в спецификации языка Java: JLS 9.6.4.4: Annotation Interface :: @Override
:
If a method declaration in class or interface Q is annotated with
@Override
, then one of the following three conditions must be true, or a compile-time error occurs:
the method overrides from Q a method declared in a supertype of Q (§8.4.8.1, §9.4.1.1)
the method is override-equivalent to a public method of Object (§4.3.2, §8.4.2)
Q is a record class (§8.10), and the method is an accessor method for a record component of Q (§8.10.3)
Также об этом упоминалось в JEP 395: Records:
- The meaning of the
@Override
annotation was extended to include the case where the annotated method is an explicitly declared accessor method for a record component.
Абстрагируясь от полезности переопределения геттера для компонента кортежа, можно сказать, что такая аннотация и переопределение позволят разве что отследить изменение / удаление элемента кортежа и потребовать изменения / удаления соответствующего геттера, о чём также говорится в JLS:
The use of
@Override
on the accessor methodint x()
ensures that if the record componentx
is modified or removed, then the corresponding accessor method must be modified or removed too.
Разумеется, при переопределении нельзя будет использовать ключевое слово super
, но можно иcпользовать ссылку на текущий компонент кортежа this.x
, или даже завести локальную переменную с тем же названием:
record Roo(int x, int y) {
@Override
public int x() {
return Math.abs(this.x);
}
@Override
public int y() {
int y = 5;
return y * this.y; // за такое могут казнить на code review
}
}