Преобразовать карту & lt; String, SomeClass & gt; к Map & lt; String, SomeUpperClass & gt; [Дубликат]

// Полностью общая сортировка для использования с gridview

public List<T> Sort_List<T>(string sortDirection, string sortExpression, List<T> data)
    {

        List<T> data_sorted = new List<T>();

        if (sortDirection == "Ascending")
        {
            data_sorted = (from n in data
                              orderby GetDynamicSortProperty(n, sortExpression) ascending
                              select n).ToList();
        }
        else if (sortDirection == "Descending")
        {
            data_sorted = (from n in data
                              orderby GetDynamicSortProperty(n, sortExpression) descending
                              select n).ToList();

        }

        return data_sorted;

    }

    public object GetDynamicSortProperty(object item, string propName)
    {
        //Use reflection to get order type
        return item.GetType().GetProperty(propName).GetValue(item, null);
    }
108
задан Riley Lark 22 February 2011 в 19:08
поделиться

10 ответов

Синтаксис такого назначения присваивания использует подстановочный знак:

List<SubClass> subs = ...;
List<? extends BaseClass> bases = subs;

Важно понимать, что List<SubClass> не является взаимозаменяемым с List<BaseClass>. Код, который сохраняет ссылку на List<SubClass>, ожидает, что каждый элемент в списке будет SubClass. Если другая часть кода относится к списку как List<BaseClass>, компилятор не будет жаловаться, когда вставлены BaseClass или AnotherSubClass. Но это приведет к ClassCastException для первого фрагмента кода, который предполагает, что все в списке является SubClass.

Общие коллекции не ведут себя так же, как массивы в Java. Массивы ковариантны; то есть разрешено это делать:

SubClass[] subs = ...;
BaseClass[] bases = subs;

Это разрешено, потому что массив «знает» тип его элементов. Если кто-то пытается сохранить что-то, что не является экземпляром SubClass в массиве (с помощью ссылки bases), будет выведено исключение во время выполнения.

Общие коллекции do not «знают» свой тип компонента; эта информация «стирается» во время компиляции. Поэтому они не могут создавать исключение во время выполнения, когда происходит недопустимое хранилище. Вместо этого ClassCastException будет поднят в некоторой далекой, трудно ассоциируемой точке в коде, когда значение будет считано из коллекции. Если вы прислушаетесь к предупреждениям компилятора о безопасности типов, вы избежите ошибок этого типа во время выполнения.

135
ответ дан erickson 18 August 2018 в 02:06
поделиться
  • 1
    Следует отметить, что с помощью массивов вместо ClassCastException при извлечении объекта, который не относится к типу SubClass (или производному), при вставке вы получите исключение ArrayStoreException. – Axel 22 February 2011 в 20:56
  • 2
    Особенно спасибо за объяснение того, почему два списка нельзя считать одинаковыми. – Riley Lark 22 February 2011 в 21:05
  • 3
    если это работает, если мой BaseClass является интерфейсом? – Alina Danila 19 April 2012 в 10:57
  • 4
    @AlinaDanila Да. Он работает одинаково. – erickson 19 April 2012 в 16:44
  • 5
    Система типа Java притворяется, что массивы ковариантны, но они не являются взаимозаменяемыми, доказанными в ArrayStoreException. – Paŭlo Ebermann 8 March 2016 в 16:28

Как о литье всех элементов. Он создаст новый список, но будет ссылаться на исходные объекты из старого списка.

List<BaseClass> convertedList = listOfSubClass.map(x -> (BaseClass)x).collect(Collectors.toList());
0
ответ дан drordk 18 August 2018 в 02:06
поделиться

Как пояснил @erickson, если вам действительно нужна ссылка на исходный список, убедитесь, что ни один код не добавляет ничего в этот список, если вы когда-нибудь захотите использовать его снова в своем первоначальном объявлении. Самый простой способ получить это - просто передать его в простой старый список:

List<BaseClass> baseList = (List)new ArrayList<SubClass>();

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

10
ответ дан hd42 18 August 2018 в 02:06
поделиться
  • 1
    Дженерики могут быть болью! В крайнем случае этот резерв спас меня ... – tangens 9 January 2014 в 22:04

List<BaseClass> convertedList = Collections.checkedList(listOfSubClass, BaseClass.class)

1
ответ дан jtahlborn 18 August 2018 в 02:06
поделиться
  • 1
    Это не должно работать, так как для этого метода все аргументы и результат принимают один и тот же параметр типа. – Paŭlo Ebermann 22 February 2011 в 22:00
  • 2
    странно, ты прав. по какой-то причине у меня создалось впечатление, что этот метод был полезен для повышения общей коллекции. все еще можно использовать таким образом, и это обеспечит "безопасный" если вы хотите использовать suppresswarnings. – jtahlborn 23 February 2011 в 00:52

То, что вы пытаетесь сделать, очень полезно, и я считаю, что мне нужно делать это очень часто в коде, который я пишу. Пример использования:

Скажем, у нас есть интерфейс Foo, и у нас есть пакет zorking, который имеет ZorkingFooManager, который создает и управляет экземплярами package-private ZorkingFoo implements Foo. (Очень распространенный сценарий.)

Итак, ZorkingFooManager должен содержать private Collection<ZorkingFoo> zorkingFoos, но ему нужно выставить public Collection<Foo> getAllFoos().

Большинство java-программистов не подумали бы дважды прежде чем реализовать getAllFoos() как выделение нового ArrayList<Foo>, заполнив его всеми элементами из zorkingFoos и вернув его. Мне нравится развлекать мысль о том, что около 30% всех тактовых циклов, потребляемых java-кодом, работающим на миллионах компьютеров по всей планете, ничего не делает, кроме создания таких бесполезных копий ArrayLists, которые собирают микросетки после мусора после их создания.

Решение этой проблемы - это, конечно, сбрасывание коллекции. Вот лучший способ сделать это:

static <T,U extends T> List<T> downCastList( List<U> list )
{
    return castList( list );
}

Что приводит нас к функции castList():

static <T,E> List<T> castList( List<E> list )
{
    @SuppressWarnings( "unchecked" )
    List<T> result = (List<T>)list;
    return result;
}

Промежуточная переменная result необходима из-за извращение языка java:

  • return (List<T>)list; создает исключение «непроверенного броска»; Все идет нормально; но затем:
  • @SuppressWarnings( "unchecked" ) return (List<T>)list; является незаконным использованием аннотации подавления-предупреждений.

Итак, хотя это не кошерно использовать @SuppressWarnings на return, очевидно, что использовать его при назначении, поэтому дополнительная переменная «result» решает эту проблему. (Он должен быть оптимизирован либо компилятором, либо JIT в любом случае.)

1
ответ дан Mike Nakis 18 August 2018 в 02:06
поделиться

Что-то вроде этого тоже должно работать:

public static <T> List<T> convertListWithExtendableClasses(
    final List< ? extends T> originalList,
    final Class<T> clazz )
{
    final List<T> newList = new ArrayList<>();
    for ( final T item : originalList )
    {
        newList.add( item );
    }// for
    return newList;
}

Не знаю, почему clazz нужен в Eclipse ..

0
ответ дан olivervbk 18 August 2018 в 02:06
поделиться

erickson уже объяснил, почему вы не можете этого сделать, но здесь некоторые решения:

Если вы хотите только извлечь элементы из своего базового списка, в принципе ваш метод приема должен быть объявлен как принимающий List<? extends BaseClass>.

Но если это не так, и вы не можете его изменить, вы можете обернуть список с помощью Collections.unmodifiableList(...), который позволяет возвращать список супертипа параметра аргумента. (Он избегает проблемы с типами, бросая UnsupportedOperationException при попытках вставки).

29
ответ дан Paŭlo Ebermann 18 August 2018 в 02:06
поделиться

Ниже приведен полезный фрагмент, который работает. Он создает новый список массивов, но создание объекта JVM над головой является значительным.

Я видел, что другие ответы не обязательно сложны.

List<BaseClass> baselist = new ArrayList<>(sublist);
-1
ответ дан sigirisetti 18 August 2018 в 02:06
поделиться
  • 1
    Благодарим вас за этот фрагмент кода, который может оказать немедленную помощь. Правильное объяснение значительно улучшит его образовательное значение, показав why , это хорошее решение проблемы и сделает его более полезным для будущих читателей с похожими, но не идентичными , вопросов. Пожалуйста, отредактируйте свой ответ, чтобы добавить объяснение, и укажите, какие ограничения и допущения применяются. В частности, как это отличается от кода в вопросе, который создает новый список? – Toby Speight 19 July 2017 в 12:04
0
ответ дан kanaparthikiran 6 September 2018 в 17:16
поделиться
0
ответ дан kanaparthikiran 29 October 2018 в 23:17
поделиться
Другие вопросы по тегам:

Похожие вопросы: