Java Generic с ArrayList <? расширяет элемент A> add
У меня есть классы A
, B
, C
и D
, где B
extends A
, C
extends A
и D
extends A
.
У меня есть следующий ArrayList
каждый с несколькими элементами в них:
ArrayList<B> b;
ArrayList<? extends A> mix = b;
Я хотел, чтобы переменная mix
содержала элементы типа B
, C
или D
. Я попытался добавить элемент типа C
в mix
следующим образом:
mix.add(anElementOfTypeC);
Но IDE не позволяет мне это делать, и он говорит:
anElementOfTypeC не может быть преобразован в CAP # 1 методом обращения где CAP # 1 является новой переменной типа: CAP # 1 расширяет A от захват? расширяет A
Правильно ли я использовал <? extends A>
? Как я могу это решить?
Ответы
Ответ 1
ArrayList<? extends A>
означает ArrayList какого-либо неизвестного типа, который расширяет A
.
Этот тип не может быть C
, поэтому вы не можете добавить C
в ArrayList.
На самом деле, поскольку вы не знаете, что должен содержать ArrayList, вы не можете добавить ничего в ArrayList.
Если вам нужен ArrayList, который может содержать любой класс, наследующий A
, используйте ArrayList<A>
.
Ответ 2
Невозможно добавить элементы в коллекции, которые используют ? extends
.
ArrayList<? extends A>
означает, что это ArrayList
типа (ровно один), который расширяет A
. Поэтому вы можете быть уверены, что когда вы вызываете метод get
, вы получите что-то, что A. Но вы не можете добавить что-то, потому что вы не знаете, что именно содержит ArrayList
.
Ответ 3
Правильно ли я использовал <? extends A>
?
List<? extends A> list;
означает, что "список" относится к списку реализованного интерфейса объекта, а в списке могут храниться элементы, унаследованные от класса A (включая A). Другими словами, правильны следующие утверждения:
List<? extends A> listA1 = new ArrayList<A>();
List<? extends A> listB1 = new ArrayList<B>();
List<? extends A> listC1 = new ArrayList<C>();
List<? extends A> listD1 = new ArrayList<D>();
Генераторы Java - это проверка сильного типа во время компиляции.
Компилятор использует generics, чтобы убедиться, что ваш код не добавляет неправильные объекты в коллекцию.
Вы пытались добавить C
в ArrayList<B>
listB1.add(new C());
Если это разрешено, объект ArrayList<B>
будет содержать разные типы объектов (B, C).
Вот почему ссылка listB1 работает в режиме "только для чтения". Кроме того, вы можете взглянуть на этот ответ.
как решить эту проблему?
List<A> list = new ArrayList<A>();
Ответ 4
Вы можете просто объявить:
ArrayList<A> mix = new ArrayList<A>();
Вы можете добавить любой элемент класса A или любой из его подклассов в такой список. Просто, когда вы получите из этого списка, вы сможете только вызывать методы, доступные на A
.
Обратите внимание, что A
не ограничивается только "полноценным" классом: он может быть абстрактным классом или даже интерфейсом.
Ответ 5
Вы можете создать список массивов суперклассов. поэтому вы можете это сделать.
ArrayList<A> arrayList=new ArrayList<A>();
Ответ 6
Посмотрите на этот пример и выберите в соответствии с вашим требованием
package com.generic;
import java.util.ArrayList;
public class SuperExtendTest {
/**
* @param args
*/
public static void main(String[] args) {
}
public void test() throws Exception {
ArrayList<Parent> parents=new ArrayList<>();
parents.add(new Parent());
parents.add(new Child());
//parents.add(new GrandParent()); Not allowed
ArrayList<Parent> p=new ArrayList<>();
ArrayList<Child> c=new ArrayList<>();
ArrayList<GrandParent> gp=new ArrayList<>();
testExtendP(p);
//testExtendP(c); Not allowed only super type allowed no child
testExtendP(gp);
testExtends(c);
testExtends(p);
//testExtends(gp); Not allowed because GrantParent does not extends Parent
}
/**
* This Method allowed get operations for Parent
* No add
*
*/
public void testExtends(ArrayList<? extends Parent> list) throws Exception {
/* list.add(new Child());
list.add(new Parent());
list.add(new GrandParent());
// can not add
*/
Child c=(Child) list.get(0);
Parent parent=list.get(0);
GrandParent gp=list.get(0);
/**
* Unsafe collection way
*/
ArrayList list2=new ArrayList();
list.addAll(list2);
}
/**
* This Method allowed add operations for Parent and it sub types and on get it gives Object type
*
*/
public void testExtendP(ArrayList<? super Parent> list) throws Exception {
list.add(new Child());
list.add(new Parent());
//list.add(new GrandParent());
/*can not add because GrandParent can not be converted to Parent type
*
* The method add(capture#3-of ? super Parent) in the type ArrayList<capture#3-of ? super Parent> is not applicable for the arguments (GrandParent)
*
*/
Child c=(Child) list.get(0);
Parent parent=(Parent) list.get(0);
GrandParent gp=(GrandParent) list.get(0);
Object obj=list.get(0);
/**
* Unsafe collection way
*/
ArrayList list2=new ArrayList();
list.addAll(list2);
}
/**
* This Method allowed all operations for Parent and it sub types
*
*/
public void testDirect(ArrayList<Parent> list) throws Exception {
list.add(new Child());
list.add(new Parent());
//list.add(new GrandParent());
/*
* Can not add GrandParent (Normal generic rule)
*/
}
}
class GrandParent{
}
class Parent extends GrandParent{
}
class Child extends Parent{
}