【问题标题】:Java Generic with ArrayList <? extends A> add elementJava 泛型与 ArrayList <?扩展 A> 添加元素
【发布时间】:2012-12-27 16:30:54
【问题描述】:

我有课程 ABCD 其中 B 扩展 AC 扩展 AD 扩展 A

我有以下ArrayLists,每个都有一些元素:

ArrayList<B> b;
ArrayList<? extends A> mix = b;

我打算让变量mix 包含BCD 类型的元素。我尝试将C 类型的元素添加到mix 中,如下所示:

mix.add(anElementOfTypeC);

但 IDE 不允许我这样做,它说:

anElementOfTypeC 不能通过调用方法转换为 CAP#1 转换,其中 CAP#1 是一个新的类型变量: CAP#1 extends A from 捕获?扩展 A

我是否正确使用了&lt;? extends A&gt;?我该如何解决这个问题?

【问题讨论】:

  • 从您的代码提取中,mix 实际上是 ArrayList&lt;B&gt; 这里...
  • 在你的研究过程中——如果你做了一些,你有没有通过这个 SO 问题——stackoverflow.com/questions/1910892/…

标签: java generics arraylist


【解决方案1】:

无法在使用? extends 的集合中添加元素。

ArrayList&lt;? extends A&gt; 表示这是一个扩展A 的类型(正好是一个 类型)的ArrayList。所以你可以确定,当你调用 get 方法时,你会得到 is A. 但是你不能添加一些东西,因为你不知道 ArrayList 到底是什么包含。

【讨论】:

    【解决方案2】:

    查看此示例并根据您的要求进行选择

    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's 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's 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{
    
    }
    

    【讨论】:

      【解决方案3】:

      我是否正确使用了&lt;? extends A&gt;

      List&lt;? extends A&gt; list;表示'list'指的是一个对象实现的接口List,该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 泛型是一种编译时强类型检查。 编译器使用泛型来确保您的代码不会将错误的对象添加到集合中。

      您尝试在ArrayList&lt;B&gt; 中添加C

      listB1.add(new C());
      

      如果允许,对象ArrayList&lt;B&gt; 将包含不同的对象类型(B、C)。
      这就是 reference listB1 在“只读”模式下工作的原因。此外,您可以查看this answer

      如何解决?

      List<A> list = new ArrayList<A>();
      

      【讨论】:

        【解决方案4】:

        您可以创建超类类型的数组列表。所以你可以这样做。

        ArrayList<A> arrayList=new ArrayList<A>();
        

        【讨论】:

          【解决方案5】:

          你可以声明:

          ArrayList<A> mix = new ArrayList<A>();
          

          您可以将 A 类或其任何子类的任何元素添加到这样的列表中。只是当您从该列表中获取时,您将只能调用 A 上可用的方法。

          请注意,A 不限于作为“成熟”类:它可以是抽象类甚至是接口。

          【讨论】:

            【解决方案6】:

            ArrayList&lt;? extends A&gt; 表示扩展 A 的某种未知类型的 ArrayList。
            该类型可能不是C,因此您不能将C 添加到ArrayList。

            事实上,由于您不知道 ArrayList 应该包含什么,因此您无法将 anything 添加到 ArrayList。

            如果您想要一个可以容纳任何继承 A 的类的 ArrayList,请使用 ArrayList&lt;A&gt;

            【讨论】:

            • 不能添加任何东西有点太严格了。我们可以添加null,也可以将list.get(0) 添加回列表。我知道我选的太多了。 ;)
            • 然而你可以声明Class&lt;? extends A&gt; c = B.class...泛型让我很头疼:/
            • @RohitJain:不,您不能将list.get(0) 添加回列表
            • @JBNizet:我知道你在说什么;但这不是评论的主题。那是List&lt;T&gt;,不是List&lt;? extends A&gt;,这是评论的主题。
            • @JBNizet:我知道代码的含义。我并不否认元素来自List&lt;? extends A&gt; 的事实。但是在您“添加list.get(0)”的地方,它是List&lt;T&gt;。这就是区别。
            猜你喜欢
            • 2018-09-17
            • 2018-11-20
            • 1970-01-01
            • 1970-01-01
            • 2021-12-18
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多