Pull to refresh

Расширение Java: алиасы

Reading time2 min
Views7.5K
Выкладываю данный пост с целью получения обратной связи от хабра-сообщества Java-программистов. При наличии достаточного количества голосов «за» эту фичу можно будет отправить для рассмотрения в Sun.

Проблема



После длительной работы с 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'ов.
Tags:
Hubs:
Total votes 7: ↑2 and ↓5-3
Comments7

Articles