Это не компилируется, любое предложение оценивается.
...
List<Object> list = getList();
return (List<Customer>) list;
Компилятор говорит: не может отбрасывать List<Object>
до List<Customer>
Это не компилируется, любое предложение оценивается.
...
List<Object> list = getList();
return (List<Customer>) list;
Компилятор говорит: не может отбрасывать List<Object>
до List<Customer>
вы всегда можете накладывать любой объект на любой тип, вставляя его сначала в Object. в вашем случае:
(List<Customer>)(Object)list;
вы должны быть уверены, что во время выполнения список не содержит ничего, кроме объектов Customer.
Критики говорят, что такое кастинг указывает на что-то не так с вашим кодом; вы должны уметь настраивать объявления типа, чтобы избежать этого. Но дженерики Java слишком сложны, и это не идеально. Иногда вы просто не знаете, есть ли удовлетворительное решение для компилятора, даже если вы хорошо знаете типы времени выполнения и знаете, что вы пытаетесь сделать, это безопасно. В этом случае просто выполняйте грубое литье по мере необходимости, чтобы вы могли оставить работу для дома.
Это потому, что, хотя клиент является объектом, список клиентов не является списком объектов. Если бы это было так, вы могли бы поместить любой объект в список Клиентов.
В зависимости от вашего другого кода лучший ответ может отличаться. Попробуйте:
List<? extends Object> list = getList();
return (List<Customer>) list;
или
List list = getList();
return (List<Customer>) list;
Но имейте в виду, что не рекомендуется делать такие непроверенные броски.
Вы можете использовать двойной бросок.
return (List<Customer>) (List) getList();
С Java 8 Streams:
Иногда можно просто использовать метод грубой силы:
List<MyClass> mythings = (List<MyClass>) (Object) objects
Но здесь есть более универсальное решение:
List<Object> objects = Arrays.asList("String1", "String2");
List<String> strings = objects.stream()
.map(element->(String) element)
.collect(Collectors.toList());
Существует множество преимуществ, но одно из них заключается в том, что вы можете составить свой список более элегантно, если не уверены, что в нем содержится:
objects.stream()
.filter(element->element instanceof String)
.map(element->(String)element)
.collect(Collectors.toList());
Обратите внимание, что я не программист на Java, но в .NET и С# эта функция называется контравариацией или ковариацией. Я еще не углубился в эти вещи, поскольку они новы в .NET 4.0, которые я не использую, поскольку это только бета-версия, поэтому я не знаю, какой из этих двух терминов описывает вашу проблему, но позвольте мне описать техническая проблема с этим.
Предположим, вам разрешили бросить. Заметьте, я говорю "cast", так как вы сказали, но есть две операции, которые могут быть возможны, кастинг и преобразование.
Преобразование означало бы, что вы получаете новый объект списка, но вы говорите о кастинге, что означает, что вы хотите временно относиться к одному объекту как к другому типу.
Здесь проблема с этим.
Что произойдет, если будет разрешено следующее (обратите внимание, что я предполагаю, что до трансляции список объектов фактически содержит объекты Customer, иначе кастинг не будет работать даже в этой гипотетической версии java):
List<Object> list = getList();
List<Customer> customers = (List<Customer>)list;
list.Insert(0, new someOtherObjectNotACustomer());
Customer c = customers[0];
В этом случае это попытается обработать объект, который не является клиентом, в качестве клиента, и вы получите ошибку времени выполнения в одной точке, либо в форме внутри списка, либо из назначения.
Однако, как правило, универсальные данные предоставляют вам типы данных типа типа, такие как коллекции, и поскольку они любят бросать слово "гарантировано", этот тип приведения, с последующими проблемами, не допускается.
В .NET 4.0 (я знаю, ваш вопрос касался java), это будет разрешено в некоторых очень конкретных случаях, когда компилятор может гарантировать, что операции, которые вы делаете, безопасны, но в общем смысле этот тип бросок не будет разрешен. То же самое можно сказать и о java, хотя я не уверен в каких-либо планах введения ковариации и контравариантности в язык Java.
Надеюсь, кто-то с лучшим знанием java, чем я, может рассказать вам о специфике будущего java или реализации.
Другим подходом будет использование потока java 8.
List<Customer> customer = myObjects.stream()
.filter(Customer.class::isInstance)
.map(Customer.class::cast)
.collect(toList());
Вы должны просто перебирать список и бросать все объекты по одному
List<Customer> cusList = new ArrayList<Customer>();
for(Object o: list){
cusList.add((Customer)o);
}
return cusList;
list.stream().forEach(x->cusList.add((Customer)x))
return cuslist;
Вы не можете, потому что List<Object>
и List<Customer>
не находятся в одном дереве наследования.
Вы можете добавить новый конструктор в класс List<Customer>
, который принимает List<Object>
, а затем перебирает список, отбрасывая каждый Object
до Customer
и добавляя его в свою коллекцию. Имейте в виду, что может произойти недопустимое исключение броска, если вызывающий List<Object>
содержит то, что не является Customer
.
Точка общих списков состоит в том, чтобы ограничить их определенными типами. Вы пытаетесь взять список, который может иметь что-нибудь в нем (Заказы, Продукты и т.д.) И втиснуть его в список, который может принимать только клиенты.
Лучше всего создать новый List<Customer>
, выполнить итерацию через List<Object>
, добавить каждый элемент в новый список и вернуть его.
Как указывали другие, вы не можете их применять, так как List<Object>
не является List<Customer>
. Что вы можете сделать, это определить представление в списке, который выполняет проверку типа на месте. Используя Коллекции Google, которые будут:
return Lists.transform(list, new Function<Object, Customer>() {
public Customer apply(Object from) {
if (from instanceof Customer) {
return (Customer)from;
}
return null; // or throw an exception, or do something else that makes sense.
}
});
В зависимости от того, что вы хотите сделать с этим списком, вам может даже не понадобиться отбрасывать его на List<Customer>
. Если вы хотите добавить в список объекты Customer
, вы можете объявить их следующим образом:
...
List<Object> list = getList();
return (List<? super Customer>) list;
Это законно (ну, не только юридически, но правильно - список имеет "некоторый супертип для Клиента" ), и если вы собираетесь передать его в метод, который будет просто добавлять объекты в список то для этого достаточно общих общих оценок.
С другой стороны, если вы хотите извлекать объекты из списка и набирать их строго как клиенты - тогда вам не повезло, и это правильно. Поскольку список является List<Object>
, нет никаких гарантий, что содержимое является клиентом, поэтому вам придется предоставить свое собственное кастинг при поиске. (Или действительно, абсолютно, вдвойне уверен, что список будет содержать только Customers
и использовать двойное нажатие из одного из других ответов, но поймите, что вы полностью обходите безопасность типа компиляции, которую вы получаете от дженерики в этом случае).
В целом, всегда полезно рассматривать максимально широкие общие границы, которые были бы приемлемы при написании метода, вдвойне, если он будет использоваться в качестве библиотечного метода. Если вы только собираетесь читать из списка, используйте List<? extends T>
вместо List<T>
, например - это дает вашим абонентам гораздо больше возможностей в аргументах, которые они могут передать, и означает, что они с меньшей вероятностью столкнутся с возможными проблемами подобный тому, который у вас здесь.
Вы можете создать новый список и добавить к нему элементы:
Например:
List<A> a = getListOfA();
List<Object> newList = new ArrayList<>();
newList.addAll(a);
Аналогично Божо выше. Вы можете сделать некоторое обходное решение здесь (хотя мне это не нравится) с помощью этого метода:
public <T> List<T> convert(List list, T t){
return list;
}
Да. Он перечислит ваш список в ваш требуемый общий тип.
В данном случае выше вы можете сделать такой код:
List<Object> list = getList();
return convert(list, new Customer());
Не самый эффективный подход, но:
List<Customer> customers = new ArrayList<Customers>(getList());