Выкладываю данный пост с целью получения обратной связи от хабра-сообщества Java-программистов. При наличии достаточного количества голосов «за» эту фичу можно будет отправить для рассмотрения в Sun.
После длительной работы с Java 5 и Java 6 и небольшой аналитики я пришел к тому, что generic'и в Java имеют ряд ограничений, которые не дают реализовать решение красивым способом, и обходить их порой приходится очень нетривиально. Данное высказывание относится к разработке подсистем, которые активно используют generic'и (доходит до 3-4 generic-типов со сложной иерархией в описании класса).
Приведу примеры кода, которые явно указывают на данные ограничения, а также неудобство использования (рассматривать только синтаксис):
Для решения о��вученных проблемы и неудобства использования, снижающего читаемость кода, предлагается расширить синтаксис языка и ввести алиасы (aliases).
Алиас представляет собой generic-тип, объявляемый на основе других generic-типов, который может использоваться в пределах видимости.
Проще всего показать на примере. Преобразуем приведенный выше код с использованием алиасов:
Предполагается, что алиасы никак не будут отражены в байт-коде, т.е. они фактически являются расширением синтаксиса языка, но не семантики. Также они позволяют зафиксировать generic-тип, что в некоторых случаях (см. пример выше) позволяет избежать cast-ов и warning'ов.
Проблема
После длительной работы с Java 5 и Java 6 и небольшой аналитики я пришел к тому, что generic'и в Java имеют ряд ограничений, которые не дают реализовать решение красивым способом, и обходить их порой приходится очень нетривиально. Данное высказывание относится к разработке подсистем, которые активно используют generic'и (доходит до 3-4 generic-типов со сложной иерархией в описании класса).
Приведу примеры кода, которые явно указывают на данные ограничения, а также неудобство использования (рассматривать только синтаксис):
public class A {
public <X> void method(List<? extends X> list) {
// processElement(list, list.get(0)); - compilation error
processElement((List) list, (Object) list.get(0)); // compilation warning
}
public <T> void processElement(List<T> list, T object) {
}
public static class B<T extends I1 & I2> {
}
// Приходится повторять объявления generic-типов
public static class С<T extends I1 & I2> extends A.B<T> {
}
}
Решение
Для решения о��вученных проблемы и неудобства использования, снижающего читаемость кода, предлагается расширить синтаксис языка и ввести алиасы (aliases).
Алиас представляет собой generic-тип, объявляемый на основе других generic-типов, который может использоваться в пределах видимости.
Проще всего показать на примере. Преобразуем приведенный выше код с использованием алиасов:
public class A {
public <X> void method(List<? extends X> list) {
// processElement(list, list.get(0)); - Ошибка компиляции
/*
Определение ? extends X как T для типа переменной list (т.е. List<? extends X> -> List<T>).
Видимость подобного определения ограничивается блоком.
При этом данное определение используется как же, как generic-тип T.
*/
List<T> list1 = alias<T>(list);
processElement(list1, list1.get(0)); // Корректно
}
public <T> void processElement(List<T> list, T object) {
}
/*
Алиас N может использоваться везде, где могла бы быть использована связка I1 & I3 (в generic'ах).
Алиас N может использоваться везде, где мог бы быть использован любой из интерфейсов I1 и I3.
Алиас N может дополнительно использоваться как тип переменной, возвращаемое значение метода или параметр метода.
У алиаса есть уровень доступа.
*/
public alias N = I1 & I2;
public static class B<T extends N> {
}
// Приходится повторять объявление одного generic-типа вместо сложной связки
public static class С<T extends N> extends A.B<T> {
}
}
Предполагается, что алиасы никак не будут отражены в байт-коде, т.е. они фактически являются расширением синтаксиса языка, но не семантики. Также они позволяют зафиксировать generic-тип, что в некоторых случаях (см. пример выше) позволяет избежать cast-ов и warning'ов.
