Например, допустим, у вас есть два класса:
public class TestA {}
public class TestB extends TestA{}
У меня есть метод, который возвращает a, List<TestA>
и я хотел бы привести все объекты в этом списке, TestB
чтобы в итоге я получил List<TestB>
.
приведение дженериков невозможно, но если вы определите список по-другому, в нем можно сохранить TestB:
У вас все еще есть проверка типов, когда вы используете объекты в списке.
источник
Cannot instantiate the type ArrayList<? extends TestA>
.Вы действительно не можете *:
Пример взят из этого урока Java
Предположим, есть два типа
A
иB
такиеB extends A
. Тогда следующий код верен:Предыдущий код действителен, потому что
B
является подклассомA
. Теперь, что происходит сList<A>
иList<B>
?Оказывается, что
List<B>
это не подкласс,List<A>
поэтому мы не можем написатьКроме того, мы не можем даже написать
*: Чтобы сделать возможной приведение, нам нужен общий родительский элемент для
List<A>
иList<B>
:List<?>
например. Следующее является действительным:Вы, однако, получите предупреждение. Вы можете подавить это, добавив
@SuppressWarnings("unchecked")
в свой метод.источник
С Java 8 вы действительно можете
источник
new List<TestB>
помощью цикла, приведения и приведения?Я думаю, что вы приводите в неправильном направлении, хотя ... если метод возвращает список
TestA
объектов, тогда действительно небезопасно приводить их кTestB
.По сути, вы просите компилятор позволить вам выполнять
TestB
операции с типом,TestA
который их не поддерживает.источник
Поскольку на этот вопрос часто ссылаются, и текущие ответы в основном объясняют, почему он не работает (или предлагают хакерские, опасные решения, которые я никогда не хотел бы видеть в рабочем коде), я думаю, что было бы целесообразно добавить другой ответ, показывающий подводные камни и возможное решение.
Причина, по которой это не работает в целом, уже указана в других ответах: действительно ли преобразование действительно допустимо, зависит от типов объектов, которые содержатся в исходном списке. Когда есть объекты в списке, тип которого не типа
TestB
, но другого подклассаTestA
, то бросок не действителен.Конечно, приведения могут быть действительными. Иногда у вас есть информация о типах, которые недоступны для компилятора. В этих случаях можно привести списки, но в общем случае это не рекомендуется :
Можно или ...
Последствия первого подхода (который соответствует принятому в настоящее время ответу) неуловимы. На первый взгляд может показаться, что он работает правильно. Но если в списке ввода есть неправильные типы, тогда
ClassCastException
будет выброшено a , возможно, в совершенно другом месте кода, и это может быть трудно отладить и выяснить, где неправильный элемент попал в список. Худшая проблема заключается в том, что кто-то может даже добавить недопустимые элементы после того, как список будет приведен, что еще больше затрудняет отладку.Проблема отладки этих ложных
ClassCastExceptions
может быть решена с помощьюCollections#checkedCollection
семейства методов.Фильтрация списка по типу
Более безопасный для преобразования тип из a
List<Supertype>
в aList<Subtype>
состоит в том, чтобы фактически отфильтровать список и создать новый список, который содержит только элементы определенного типа. Существует несколько степеней свободы для реализации такого метода (например, в отношении обработкиnull
записей), но одна из возможных реализаций может выглядеть следующим образом:Этот метод может использоваться для фильтрации произвольных списков (не только с заданным отношением Подтип-Супертип относительно параметров типа), как в этом примере:
источник
Вы не можете бросить ,
List<TestB>
чтобыList<TestA>
Стив Kuo упоминает , но вы можете сбросить содержимоеList<TestA>
вList<TestB>
. Попробуйте следующее:Я не пробовал этот код, поэтому, вероятно, есть ошибки, но идея в том, что он должен перебирать объект данных, добавляя элементы (объекты TestB) в список. Я надеюсь, что это работает для вас.
источник
Лучший безопасный способ - реализовать
AbstractList
и привести элементы в исполнение. Я создалListUtil
вспомогательный класс:Вы можете использовать
cast
метод для слепого приведения объектов в списке иconvert
метод для безопасного приведения. Пример:источник
Единственный способ, которым я знаю, это скопировать:
источник
Когда вы приводите ссылку на объект, вы просто приводите тип ссылки, а не тип объекта. кастинг не изменит фактический тип объекта.
Java не имеет неявных правил для преобразования типов объектов. (В отличие от примитивов)
Вместо этого вам нужно указать, как преобразовать один тип в другой и вызвать его вручную.
Это более многословно, чем в языке с прямой поддержкой, но это работает, и вам не нужно делать это очень часто.
источник
если у вас есть объект класса
TestA
, вы не можете его привестиTestB
. каждыйTestB
естьTestA
, но не наоборот.в следующем коде:
вторая строка будет бросать
ClassCastException
.Вы можете привести
TestA
ссылку только если сам объектTestB
. например:Таким образом, вы не всегда можете привести список
TestA
к спискуTestB
.источник
Вы можете использовать
selectInstances
метод в Eclipse Collections . Однако это потребует создания новой коллекции, поэтому не будет столь же эффективным, как принятое решение, использующее кастинг.Я включил
StringBuffer
в пример, чтобы показать, чтоselectInstances
не только понижает тип, но также будет фильтровать, если коллекция содержит смешанные типы.Примечание: я являюсь коммиттером для Eclipse Collections.
источник
Это возможно из-за стирания типа. Вы найдете это
Внутренне оба списка имеют тип
List<Object>
. По этой причине вы не можете разыгрывать одно на другое - нечего разыгрывать.источник
Integer j = 42; Integer i = (Integer) j;
отлично работает, оба являются целыми числами, они оба имеют один и тот же класс, поэтому «нечего разыгрывать».Проблема в том, что ваш метод НЕ возвращает список TestA, если он содержит TestB, так что, если он был правильно напечатан? Тогда этот актерский состав:
работает так же хорошо, как вы могли бы надеяться (Eclipse предупреждает вас о неконтролируемом приведении, которое именно то, что вы делаете, так что) Так вы можете использовать это, чтобы решить вашу проблему? На самом деле вы можете из-за этого:
Именно то, что вы просили, верно? или, если быть точным:
похоже компилируется просто отлично для меня.
источник
Этот тест показывает, как привести
List<Object>
кList<MyClass>
. Но нужно обратить внимание на то, чтоobjectList
должны содержать экземпляры того же типа, что иMyClass
. И этот пример можно рассмотреть, когдаList<T>
используется. Для этого получите полеClass<T> clazz
в конструкторе и используйте его вместоMyClass.class
.источник
Это должно бы сработать
источник
Довольно странно, что приведение списка вручную до сих пор не обеспечивается некоторым набором инструментов, реализующим что-то вроде:
Конечно, это не будет проверять элементы один за другим, но это именно то, чего мы хотим здесь избежать, если мы хорошо знаем, что наша реализация предоставляет только подтип.
источник