Это не компилируется, любое предложение приветствуется.
...
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 слишком сложны и несовершенны. Иногда вы просто не знаете, есть ли красивое решение, удовлетворяющее компилятор, даже если вы очень хорошо знаете типы среды выполнения и знаете, что то, что вы пытаетесь сделать, безопасно. В этом случае просто сделайте неочищенное литье по мере необходимости, чтобы вы могли оставить работу дома.
@SuppressWarnings("unchecked"). Обратите внимание, что вы также можете использовать upcast (List)вместо to (Object).
Это потому, что, хотя клиент является объектом, список клиентов не является списком объектов. Если да, то вы можете поместить любой объект в список клиентов.
.Cast<T>()а второй вызываемый .OfType<T>(). Первый выполняет приведение к каждому элементу (выбрасывая желаемые исключения), а второй отфильтровывает элементы, которые не могут быть преобразованы (поэтому вы можете выбрать один в зависимости от сценария использования).
instanceofклиентом?
В зависимости от вашего другого кода лучший ответ может отличаться. Пытаться:
List<? extends Object> list = getList();
return (List<Customer>) list;
или
List list = getList();
return (List<Customer>) list;
Но имейте в виду, что такие непроверенные забросы делать не рекомендуется.
С потоками Java 8 :
Иногда подходит брутфорс:
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());
FluentIterableу меня работал.
Можно использовать двойной заброс.
return (List<Customer>) (List) getList();
Обратите внимание, что я не программист на Java, но в .NET и C # эта функция называется контравариантностью или ковариацией. Я еще не углублялся в эти вещи, поскольку они являются новинкой в .NET 4.0, которую я не использую, поскольку это только бета-версия, поэтому я не знаю, какой из двух терминов описывает вашу проблему, но позвольте мне описать техническая проблема с этим.
Предположим, вам разрешили кастовать. Обратите внимание: я говорю « приведение» , поскольку вы так сказали, но есть две операции, которые могут быть возможны: приведение и преобразование .
Преобразование будет означать, что вы получите новый объект списка, но вы говорите приведение, что означает, что вы хотите временно рассматривать один объект как другой тип.
Вот в чем проблема.
Что произошло бы, если бы было разрешено следующее (обратите внимание, я предполагаю, что до приведения список объектов фактически содержал только объекты Customer, иначе приведение не будет работать даже в этой гипотетической версии java):
List<Object> list = getList();
List<Customer> customers = (List<Customer>)list;
list.Insert(0, new someOtherObjectNotACustomer());
Customer c = customers[0];
В этом случае это будет попытка обработать объект, который не является клиентом, как клиент, и вы получите ошибку времени выполнения в какой-то момент, либо в форме внутри списка, либо из назначения.
Однако предполагается, что Generics предоставит вам типобезопасные типы данных, такие как коллекции, и, поскольку они любят использовать слово «гарантировано», такой тип приведения с последующими проблемами не допускается.
В .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к a Customerи добавляя его в вашу коллекцию. Имейте в виду, что недопустимое исключение приведения может возникнуть, если вызывающий List<Object>содержит что-то, что не являетсяCustomer .
Смысл общих списков в том, чтобы ограничить их определенными типами. Вы пытаетесь взять список, в котором может быть что угодно (заказы, продукты и т. Д.), И втиснуть его в список, который может принимать только клиентов.
Лучше всего создать новый List<Customer>, перебрать List<Object>, добавить каждый элемент в новый список и вернуть его.
Как отмечали другие, вы не можете безопасно использовать их, поскольку a 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.
}
});
Аналогично с Божо выше. Здесь вы можете найти обходной путь (хотя мне это не нравится) с помощью этого метода:
public <T> List<T> convert(List list, T t){
return list;
}
Да. Он переведет ваш список в требуемый общий тип.
В приведенном выше случае вы можете сделать такой код:
List<Object> list = getList();
return convert(list, new Customer());
В зависимости от того, что вы хотите делать со списком, вам может даже не потребоваться преобразовывать его в файл List<Customer>. Если вы хотите только добавить Customerобъекты в список, вы можете объявить его следующим образом:
...
List<Object> list = getList();
return (List<? super Customer>) list;
Это законно (ну, не только законно, но и правильно - список имеет «некоторый супертип для клиента»), и если вы собираетесь передать его в метод, который будет просто добавлять объекты в список, то приведенный выше для этого достаточно общих оценок.
С другой стороны, если вы хотите получить объекты из списка и строго типизировать их как Customers, тогда вам не повезло, и это правильно. Поскольку список является List<Object>составным, нет никакой гарантии, что содержимое принадлежит клиентам, поэтому вам придется предоставить собственное приведение при поиске. (Или будьте действительно, абсолютно, вдвойне уверены, что список будет содержать Customersи использовать только двойное приведение из одного из других ответов, но поймите, что вы полностью обходите безопасность типов во время компиляции, которую вы получаете от дженериков в этом кейс).
Вообще говоря, всегда полезно учитывать как можно более широкие общие границы, которые были бы приемлемы при написании метода, вдвойне, если он будет использоваться в качестве библиотечного метода. Если вы собираетесь читать только из списка, используйте , например , List<? extends T>вместо List<T>- это дает вашим вызывающим абонентам гораздо больше возможностей для аргументов, которые они могут передать, и означает, что они с меньшей вероятностью столкнутся с проблемами, которых можно избежать, аналогичными тем, которые вы ' здесь.