У меня есть код, по которому я хочу разобраться, как работает рекурсивные generics. Смысл задачи в том, что-бы метод compareTo
, принимал для сравнения, только объекты того типа, на котором он вызывается. То есть от класса Product
наследуется Milk
, и Phone
, и объект Phone
не должен принимать для сравнения в compareTo
, объект Milk
, только Phone
. И есть место, которое я не как не могу понять. Это место Product<T extends Product<T>>
автор кода утверждает, что для правильной работы, необходимо параметризировать Product<T>
. Но код работает точно так же, если написать Product<T extends Product>
. Объясните пожалуйста, это я что-то не понимаю, или автор перемудрил. И если первое, то почему так?
class Product<T extends Product<T>> implements Comparable<T> {
private int price;
Product(int price) {
this.price = price;
}
public int getPrice() {
return price;
}
@Override
public int compareTo(T o) {
return o.getPrice() - this.price;
}
}
class Milk extends Product<Milk> {
Milk(int price) {
super(price);
}
}
class Phone extends Product<Phone> {
Phone(int price) {
super(price);
}
}
Использование T extends Product<T>
вместо T extends Product
не препятствует созданию классов, у которых в качестве T
участвует другой тип или T
вообще не указан:
class Phone extends Product<Milk> { ... }
class Chair extends Product { ... }
Однако в случае использования T extends Product<T>
не получится создать такой класс:
class CustomChair extends Product<Chair>
потому что это приведёт к ошибке компиляции:
error: type argument Chair is not within bounds of type-variable T
class CustomChair extends Product
where T is a type-variable:
T extends Product declared in class Product
Ошибка компиляции будет даже если класс Chair
задан так:
class Chair extends Product<Milk> { ... }
Так как в обоих случаях класс Chair
не подходит в качестве T
из-за требования T extends Product<T>
. Вот Chair extends Product<Chair>
подошло бы.
Можно сказать, что T extends Product<T>
задаёт более жесткие условия для T
, чем T extends Product
. Где-то это нужно, где-то - нет.
Например, если бы в классе Product
были такие поля:
private T friend, friendOfFriend;
и такие методы:
public void setFriend(T t)
{
friend = t;
friendOfFriend = t.getFriend();
}
public T getFriend() { return friend; }
public T getFriendOfFriend() { return friendOfFriend; }
То в случае использования T extends Product
пришлось бы использовать
friendOfFriend = (T)t.getFriend();
для приведения Product
к T
, что чревато ClassCastException
.
Например, при всё тех же class Chair extends Product
и class CustomChair extends Product<Chair>
:
Milk milk = new Milk(1);
Chair chair = new Chair(10);
chair.setFriend(milk);
CustomChair customChair = new CustomChair(20);
customChair.setFriend(chair);
Chair c = customChair.getFriendOfFriend();
В реальных условиях, надеюсь, никто не пытается подружить стул с молоком, но всё же.
С T extends Product<T>
молоко получится подружить только с молоком:
Milk milk1 = new Milk(1);
Milk milk2 = new Milk(2);
Milk milk3 = new Milk(3);
milk2.setFriend(milk3);
milk1.setFriend(milk2);
Milk m = milk1.getFriendOfFriend();
System.out.println(m.getPrice());
Кофе для программистов: как напиток влияет на продуктивность кодеров?
Рекламные вывески: как привлечь внимание и увеличить продажи
Стратегії та тренди в SMM - Технології, що формують майбутнє сьогодні
Выделенный сервер, что это, для чего нужен и какие характеристики важны?
Современные решения для бизнеса: как облачные и виртуальные технологии меняют рынок
В общем, проблема такая: мне нужно проверить находится ли _курсор в объекте JTextField
Необходимо прочитать все целые числа (integer) из файла и найти максимальное число, так же необходимо найти все индексы этого числа