Подтвердить что ты не робот

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>? Как я могу это решить?

4b9b3361

Ответ 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{

}