Обобщения с ArrayAdapters - PullRequest
       0

Обобщения с ArrayAdapters

7 голосов
/ 19 августа 2011

Я столкнулся с проблемой при попытке создать универсальный ArrayAdapter.Вероятно, это связано с моим ограниченным пониманием дженериков в Java, и я надеялся, что кто-нибудь сможет меня поправить.В основном у меня есть абстрактный базовый класс адаптера:

public abstract class BaseAdapter<T> extends ArrayAdapter<T>
{
    ....
    private List<T> items;
    ....
    protected abstract List<T> build(JSONArray jsonArray);
    ....
    @Override
    public T getItem(int position)
    {
        return items.get(position);
    }
    ....
}

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

public class MyAdapter extends BaseAdapter<BaseModel>
{
    ....
    @Override
    protected List<BaseModel> build(JSONArray jsonArray)
    {
        if (useBaseModel())
        {
            return BaseModel.buildBaseModels(jsonArray); //returns List<BaseModel>
        }
        else
        {
            return SubclassModel.buildSubclassModels(jsonArray); //returns List<SubclassModel>
        }
    }
    ....
}

Модели определены как:

public class BaseModel{...}

public class SubclassModel extends BaseModel{....}

Это не компилируется, так как, хотя SubclassModel расширяет BaseModel, их списки не эквивалентны.Этот поток ( Наиболее эффективный способ приведения Списка к Списку ) объясняет так же много и говорит использовать вместо этого:

List<? extends BaseModel> 

Когда я изменяю на:

public class MyAdapter extends BaseAdapter<? extends BaseModel> 
{
    ...
    protected List<? extends BaseModel> build(JSONArray jsonArray)
    ...
 }

ошибки в методе сборки исчезли, но теперь есть ошибка уровня класса, заявляющая: getItem (int) в BaseAdapter конфликтует с getItem (int) в android.widget.ArrayAdapter;попытка использовать несовместимый тип возвращаемого значения.

Кажется, что getItem должен возвращать тип?расширяет BaseModel, что это такое - кто-нибудь может посоветовать?

Спасибо!

Ответы [ 2 ]

7 голосов
/ 19 августа 2011

Хм, мой Java SDK даже не позволяет мне компилировать

public class MyAdapter extends BaseAdapter<? extends BaseModel> 

Ожидается неограниченный класс или интерфейс после extends. Но это не имеет значения, решением вашей проблемы является изменение класса BaseAdapter, если это опция:

public abstract class BaseAdapter<T> extends ArrayAdapter<T>
{
    ....
    private List<T> items;
    ....
    protected abstract List<? extends T> build(JSONArray jsonArray);
    ....
    @Override
    public T getItem(int position)
    {
        return items.get(position);
    }
}

Тогда

public class MyAdapter extends BaseAdapter<BaseModel> 
{
    ...
    protected List<? extends BaseModel> build(JSONArray jsonArray)
    ...
}

с предыдущим кодом будет работать.

Редактировать:

Забыл объяснить, почему ваше первое решение не сработало:

Спецификация Language говорит

Подтипирование не распространяется на универсальные типы: T <: U не означает, что C <: C. </p>

Это означает, что хотя SubclassModel расширяет BaseModel, это не означает, что List расширяет List.

0 голосов
/ 19 августа 2011

Я не могу скомпилировать

public class MyAdapter extends BaseAdapter<? extends BaseModel> 

Дает мне сообщение об ошибке: «В супертипе не может быть подстановочный знак».

Что работает для меня, это -

public abstract class BaseAdapter<T> extends ArrayAdapter<T>
{
    private List<? extends T> items;
    protected abstract List<? extends T> build(JSONArray jsonArray);
}

и это

public class MyAdapter extends BaseAdapter<BaseModel> 
{
    protected List<? extends BaseModel> build(JSONArray jsonArray);
}
...