tgoop.com/java_fillthegaps/501
Create:
Last Update:
Last Update:
Self-referential generic, часть 1
Кто участвовал в декабрьском адвенте, точно помнит, что еnum
компилируется в наследник класса Enum
:
public enum Animal {WOLF, TIGER}↓
public class Animal extends Enum {Подробнее об этом и енамах в целом можно почитать тут — раз, два и три.
public static final Animal WOLF;
public static final Animal TIGER;
}
В определении класса
Enum
используется конструкция, которая называется self-referential generic (или self-bound type, или recursive generic):EnumᐸE extends EnumᐸEᐳᐳВ этом посте расскажу, что это такое и зачем нужно.
Чтобы понять, какая проблема решается, представим, что этой конструкции нет. И определение енама выглядит так:
public abstract class MyEnum implements ComparableᐸMyEnumᐳПользователь определяет enum Animal и enum Converter. Компилятор превращает это в классы
Animal extends MyEnumКаждый класс должен реализовать интерфейс
Converter extends MyEnum
ComparableᐸMyEnumᐳ
и метод compareTo
. Чтобы не сравнивать животных и конвертеры, придётся использовать instanceof
: public final int compareTo(MyEnum o) {В самом
if (o instanceOf Animal other) {
// сравниваем зверюшек
// return ...
}
throw IllegalArgumentException();
}
instanceOf
нет ничего плохого. Тем более этот код генерируется при компиляции и остаётся за кадром.Есть более важный момент. Пользователь может спокойно сравнить животное и конвертер, ошибка возникнет только в рантайме. Это выглядит странно, ведь enum Animal и enum Converter никак не связаны между собой.
Здесь дженерик выходит на сцену:
public abstract class EnumᐸE extends EnumᐸEᐳᐳ implements ComparableᐸEᐳ🔸 Добавляем параметр E, совместимый с классом
Enum
🔸 Используем E в интерфейсе Comparable
🔸 Компилируем enum Animal
вpublic class Animal extends EnumᐸAnimalᐳ🔸 Теперь
Comparable
использует тип Animal, и метод compareTo
станет таким:public int compareTo(Animal o)✅ Убрали
instanceOf
, код стал меньше и быстрее✅ При компиляции происходит проверка типов:
Animal zebra = Animal.ZEBRA;❌
Converter csv = Converter.CSV;
zebra.compareTo(csv);
// не скомпилируется!Self-referential generic позволяет использовать дочерний тип в интерфейсах и методах родителя. Для некоторых кейсов этот приём здорово упрощает код и снижает количество ошибок. В следующем посте покажу ещё один пример использования.
Ответ на вопрос перед постом: self-referential generic помогает ограничить сравнение разных enum между собой.
BY Java: fill the gaps
Share with your friend now:
tgoop.com/java_fillthegaps/501