Страницы

Поиск по вопросам

пятница, 14 июня 2019 г.

Как работает рекурсивный generic?

У меня есть код, по которому я хочу разобраться, как работает рекурсивные generics. Смысл задачи в том, что-бы метод compareTo, принимал для сравнения, только объекты того типа, на котором он вызывается. То есть от класса Product наследуется Milk, и Phone, и объект Phone не должен принимать для сравнения в compareTo, объект Milk, только Phone. И есть место, которое я не как не могу понять. Это место Product> автор кода утверждает, что для правильной работы, необходимо параметризировать Product. Но код работает точно так же, если написать Product. Объясните пожалуйста, это я что-то не понимаю, или автор перемудрил. И если первое, то почему так?
class Product> implements Comparable { 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(int price) { super(price); } }
class Phone extends Product { Phone(int price) { super(price); } }


Ответ

Использование T extends Product вместо T extends Product не препятствует созданию классов, у которых в качестве T участвует другой тип или T вообще не указан:
class Phone extends Product { ... }
class Chair extends Product { ... }
Однако в случае использования T extends Product не получится создать такой класс:
class CustomChair extends Product
потому что это приведёт к ошибке компиляции:
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 { ... }
Так как в обоих случаях класс Chair не подходит в качестве T из-за требования T extends Product. Вот Chair extends Product подошло бы.
Можно сказать, что T extends Product задаёт более жесткие условия для 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
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 молоко получится подружить только с молоком:
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());

Комментариев нет:

Отправить комментарий