Це не складається, будь-яка пропозиція оцінена.
...
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;
Ви повинні бути впевнені, що під час виконання список не містить нічого, крім об'єктів Клієнта.
Критики кажуть, що таке кастинг вказує на те, що у вашому коді щось не так; ви повинні мати змогу налаштувати декларації типу, щоб уникнути цього. Але дженерики Java занадто складні, і вона не є досконалою. Іноді ви просто не знаєте, чи є гарне рішення для задоволення компілятора, хоча ви дуже добре знаєте типи виконання та знаєте, що намагаєтесь зробити, це безпечно. У цьому випадку просто виконайте сирий кастинг за потребою, щоб ви могли залишити роботу вдома.
@SuppressWarnings("unchecked"). Зауважте, що (List)замість цього ви також можете поновитись (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, які я не використовую, оскільки це лише бета-версія, тому я не знаю, який із двох термінів описує вашу проблему, але дозвольте мені описати технічне питання з цим.
Давайте припустимо, що вам дозволили робити кастинг. Зауважте, я кажу в ролі , оскільки це ви сказали, але можливі дві операції: кастинг і перетворення .
Перетворення означало б, що ви отримуєте новий об’єкт списку, але ви кажете, що означає, що ви хочете тимчасово ставитися до одного об’єкта як до іншого типу.
Ось проблема з цим.
Що буде, якби було дозволено наступне (зауважте, я припускаю, що перед складом список об’єктів насправді містить лише об'єкти клієнта, інакше кастинг не працюватиме навіть у цій гіпотетичній версії 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.
}
});
Аналогічно з Божо вище. Тут ви можете зробити обхідне рішення (хоча мені це не подобається) за допомогою цього методу:
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;
Це законно (ну, не просто юридично, але правильно - список має "деякий супертип для Клієнта"), і якщо ви збираєтеся передати його в метод, який буде просто додавати об'єкти до списку, то вище родових меж для цього достатньо.
З іншого боку, якщо ви хочете отримати об'єкти зі списку та набрати їх напевно як Клієнти - тоді вам не пощастить, і це правильно. Оскільки у списку List<Object>немає гарантії, що вміст є клієнтами, тому вам доведеться надати власний кастинг для пошуку. (Або по-справжньому, абсолютно, вдвічі впевнений, що список буде містити Customersта використовувати лише подвійний переклад з однієї з інших відповідей, але розумійте, що ви повністю обходите безпеку типу компіляції, яку ви отримуєте від дженериків у цьому випадок).
Загалом, завжди добре враховувати найширші загальні межі, які були б прийнятні при написанні методу, вдвічі, якщо це буде використовуватися як бібліотечний метод. Якщо ви збираєтеся читати лише зі списку, використовуйте List<? extends T>замість List<T>, наприклад, це дає вашим абонентам набагато більше сфери в аргументах, які вони можуть передавати, і означає, що вони рідше стикаються з проблемами, які можна уникнути, аналогічно тому, яке ви ' є тут.