Предположим, что есть класс:
public class TOP <T extends TOP> {
private T element;
public TOP <T> set (T element) {
this.element = element;
return this;
}
public T get () {
return element;
}
}
И класс наследник
public class A extends TOP <A> {
// some code;
}
И вот в чем загвоздка, если я пишу такой код
public class TOP <T> {
private T element;
public TOP <T> set (T element) {
this.element = element;
return this;
}
public T get () {
return element;
}
}
И класс наследник
public class A extends TOP <A> {
// some code
}
Они работают аналогично. В чем разница? Желательно на примерах :)
Не знаю, насколько ответ относится к вопросу, но, мне кажется, он будет полезен.
Предположим, у нас есть базовый класс и его наследник:
public class Base {
int propertyBase;
}
public class Derived extends Base {
int propertyDerived;
}
В каждом из классов есть по свойству. Мы можем написать сеттеры для этих свойств:
public class Base {
int propertyBase;
public Base setPropertyBase(int propertyBase) {
this.propertyBase = propertyBase;
return this;
}
}
public class Derived extends Base {
int propertyDerived;
public Derived setPropertyDerived(int propertyDerived) {
this.propertyDerived = propertyDerived;
return this;
}
}
Теперь, чтобы в одну строчку создать новый экземпляр класса Derived, с инициализацией обоих свойств, нужно написать что-то вроде
Derived derived = new Derived()
.setPropertyDerived(77)
.setPropertyBase(77);
Но есть одна проблема — этот код не скомпилируется, так как возвращаемый тип метода setPropertyBase равен Base — не может быть неявно преобразован к Derived.
Разумеется, мы не хотим писать явных кастов. Таким образом, наиболее модный способ — параметризовать класс Base шаблонным параметром, который будет «равен» классу-наследнику. Тогда мы сможем изменить метод setPropertyBase, чтобы его возвращаемый тип был равен классу-наследнику.
public class Base<T extends Base> {
int propertyBase;
public T setPropertyBase(int propertyBase) {
this.propertyBase = propertyBase;
return (T) this;
}
}
public class Derived extends Base<Derived> {
int propertyDerived;
public Derived setPropertyDerived(int propertyDerived) {
this.propertyDerived = propertyDerived;
return this;
}
}
Теперь код выше успешно скомпилируется.
Этот подход называется «Текучий интерфейс».
Как развивать веб-проекты в 2026 году: технологии, контент E-E-A-T и факторы доверия
Современные инструменты для криптотрейдинга: как технологии помогают принимать решения
Апостиль в Лос-Анджелесе без лишних нервов и бумажной волокиты
Основные этапы разработки сайта для стоматологической клиники