В чем отличие между <T> и <T extends someClass>?

251
07 июня 2017, 02:28

Предположим, что есть класс:

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
}

Они работают аналогично. В чем разница? Желательно на примерах :)

Answer 1

Не знаю, насколько ответ относится к вопросу, но, мне кажется, он будет полезен.

Предположим, у нас есть базовый класс и его наследник:

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;
    }
}

Теперь код выше успешно скомпилируется.

Этот подход называется «Текучий интерфейс».

READ ALSO
Убрать анимацию нажатия

Убрать анимацию нажатия

Как можно убрать анимацию нажатия на элементы listview? чтобы они не выделялись при нажатии

250
Получение данных от USB устройств - Java SE, usb4java

Получение данных от USB устройств - Java SE, usb4java

Подскажите как реализовать или если есть, то пример реализации, получения данных от usb девайсапробовал usb4Java, но нормальных доков не нашел...

234
usb4java - USB error 5: Unable to read config descriptor: Entity not found

usb4java - USB error 5: Unable to read config descriptor: Entity not found

Делаю дамп устройствПолучаю такую ошибку:

268
Добавление элементов в коллекцию и ее сортировка

Добавление элементов в коллекцию и ее сортировка

Подскажи пожалуйста, как добавлять элементы в коллекцию LinkedList при этом всегда держать отсортированную структуру? Сортировка при каждом...

207