Хобрук: Ваш путь к мастерству в программировании

java — Доступ к вложенному универсальному типу

У меня есть два класса, которые используют общие типы (A, B). Мой вопрос: как лучше всего работать с первым универсальным типом (TA) изнутри B? Вот упрощенный пример:

public class A<TListItemsType>
{
    List<TListItemsType> list = new LinkedList<TListItemsType>();
    public List<TListItemsType> getList()
    {
        return list;
    }   
}
public class B<TContainderType extends A>
{
    TContainderType temp = null;
    public B(TContainderType cont)
    {
        temp=cont;  
    }
    public void DoWork()
    {
        for (TListItemsType item : temp.getList())
        {
            System.out.println(item);
        }
    }
}

Я пробовал решение, предложенное здесь -

public class B<TContainderType extends A<TListItemsType>>
{
    TContainderType temp = null;
    public B(TContainderType cont)
    {
        temp=cont;  
    }
    public void DoWork()
    {
        for (TListItemsType item : temp.getList())
        {
            System.out.println(item);
        }
    }
}

И это работает до тех пор, пока используется предопределенный тип, такой как Integer или String, к сожалению, это не работает, поскольку компилятор не распознает универсальное имя класса.

Поэтому пошел дальше и попытался настроить другой общий тип, а затем использовать его внутри расширений:

public class B<TListItemsType, TContainderType extends A<TListItemsType>>
{
    TContainderType temp = null;
    public B(TContainderType cont)
    {
        temp=cont;  
    }
    public void DoWork()
    {
        for (TListItemsType item : temp.getList())
        {
            System.out.println(item);
        }
    }
}

И это действительно работает, но пахнет не так. Есть ли другой способ использовать универсальный тип, используемый в другом универсальном типе?

04.12.2012

  • Извините, но очень раздражает, что ваши фактические имена классов представляют собой односимвольные имена, а параметры вашего типа длинные. Должно быть наоборот, и это делает код невероятно трудным для чтения. 04.12.2012
  • Что ж, @biziclop, я думаю, довольно ясно, что в этом случае важной частью является универсальный тип, а не имя класса, и что это очень упрощенный пример: присвоение односимвольных имен дженерикам сделало бы код совершенно нечитаемым. Могу заверить, что в RL классы имеют полные названия :) 04.12.2012
  • Верно и обратное: это делает код нечитаемым. Односимвольные имена для дженериков — это нормально, это то, к чему все привыкли. 05.12.2012

Ответы:


1

То, как вы это сделали, используя B<TListItemsType, TContainderType extends A<TListItemsType>>, мне нравится...

Причина, по которой это имеет смысл, заключается в том, что вашему классу B теперь действительно нужны два параметра для его описания: TListItemsType и TContainderType. Фактически, вы даже явно используете TListItemsType в своей функции DoWork() внутри B. Поэтому справедливо, что вам нужно передать его в качестве параметра. В противном случае компилятор даже не знал бы, что вы имеете в виду внутри вашей функции DoWork(), так как вы могли бы точно так же написать определение класса следующим образом:

public class B<TWorkItemType, TContainderType extends A<TWorkItemType>>
{
    //...

    public void DoWork()
    {
        for (TWorkItemType item : temp.getList())
        {
            System.out.println(item);
        }
    }
}

(Обратите внимание, что я полностью переименовал тип, но только в B, а не в A!)

Если бы вам просто требовалось использовать то же имя TListItemsType, которое используется в определении A, вы были бы весьма ограничены в том, что вы могли бы делать с дженериками. Например, вы не можете принять один тип extends List<E>, а другой extends Enum<E>, так как оба они используют <E> в качестве универсального идентификатора.

Надеюсь, теперь пахнет лучше... :)

04.12.2012

2

Из вашего вопроса действительно неясно, какие требования вам нужны и для чего вам нужно использовать TListItemsType. Если вам действительно не нужно осмысленно использовать TListItemsType (как это выглядит в вашем примере), вы можете исключить его и просто расширить TContainderType A<?>:

public class B<TContainderType extends A<?>>
{
    TContainderType temp = null;
    public B(TContainderType cont)
    {
        temp=cont;  
    }
    public void DoWork()
    {
        for (Object item : temp.getList())
        {
            System.out.println(item);
        }
    }
}

и в этом отношении, если вы не собираетесь возвращать TContainderType или использовать его в параметре типа или что-то в этом роде, вы даже можете исключить это:

public class B
{
    A<?> temp = null;
    public B(A<?> cont)
    {
        temp=cont;  
    }
    public void DoWork()
    {
        for (Object item : temp.getList())
        {
            System.out.println(item);
        }
    }
}

Так что все зависит от того, что вам нужно сделать. Ваш пример мало что делает, поэтому из него можно удалить много вещей, но это может быть не то, что вам действительно нужно.

04.12.2012
  • Очевидно, мне не нужно печатать элементы, как говорит мой вопрос - мне нужно работать с элементом. 04.12.2012
  • Новые материалы

    Управление DOM для чайников вроде меня
    Одной из первых вещей, которую мы рассмотрели, когда начали изучать Javascript во Flatiron, была модель DOM. Кто он? Чем он занимается? Он больше машина, чем человек? Ну да довольно много. ДОМ..

    Что такое структура данных?
    Структура данных хранит и извлекает данные. Все, что обеспечивает эти две функции, является структурой данных . Период. Вы можете пропустить оставшуюся часть статьи, если ответ..

    мои январские чтения по программированию
    Эрик Эллиот Программирование приложения JavaScript Эл Свейгарт «Автоматизируйте скучные вещи с помощью Python» Прогрессивное веб-приложение Google..

    Создание ассоциаций секвелизации с помощью инструмента командной строки Sequelize
    Sequelize - популярный, простой в использовании инструмент объектно-реляционного сопоставления (ORM) JavaScript, который работает с базами данных SQL. Довольно просто начать новый проект с..

    Искусственный интеллект в юридической отрасли - пример прогнозирования судебных решений с помощью глубокого обучения
    На протяжении всей истории люди полагались на суды, присяжных, королей и королев в отправлении правосудия. Сегодня способность судов обеспечивать справедливое и быстрое правосудие для своих..

    Введение в машинное обучение для обнаружения аномалий (часть 1)
    Тщательно созданный, тщательно спроектированный ресурс для специалистов по данным. Часть 1 Главы 03 из Руководства по машинному обучению для обнаружения аномалий Внимание! Прежде чем вы..

    Начало работы с Pulumi в Digital Ocean
    Цифровой океан (ДО) — отличная альтернатива многим другим поставщикам облачных услуг. DO предоставляет простой и понятный пользовательский интерфейс, упрощающий управление инфраструктурой и..