Это не компилируется, любое предложение приветствуется.
...
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>
- это дает вашим вызывающим абонентам гораздо больше возможностей для аргументов, которые они могут передать, и означает, что они с меньшей вероятностью столкнутся с проблемами, которых можно избежать, аналогичными тем, которые вы ' здесь.