【问题标题】:ArrayList and Arrays.asList works differently for Collection in case of inheritance在继承的情况下,ArrayList 和 Arrays.asList 对 Collection 的工作方式不同
【发布时间】:2018-12-06 03:42:46
【问题描述】:
public class SS {
    public static void main(String[] args) {
        SS s = new SS();
        List<B> list = new ArrayList<>();

        s.checkWithoutInheritance(Arrays.asList(new B()));  //Works fine
        s.checkWithoutInheritance(list);    //----------Not working

        s.checkWithInheritance(Arrays.asList(new B())); //Works fine
        s.checkWithInheritance(list);   //Works fine
    }

    private void checkWithInheritance(final Collection<? extends A> s) {
    }

    private void checkWithoutInheritance(final Collection<A> s) {
    }
}


class A {
};

class B extends A {
};

【问题讨论】:

    标签: java generics inheritance collections


    【解决方案1】:

    它们的行为并没有不同,您使用它们的方式不同。

    在这里你让编译器决定Arrays.asList返回的List的类型,并且编译器决定它应该是List&lt;A&gt;,给定checkWithoutInheritance()所需的参数:

    s.checkWithoutInheritance(Arrays.asList(new B()));
    

    在这里,您将List&lt;B&gt; 传递给方法,因此编译器别无选择,只能失败:

    List<B> list = new ArrayList<>();
    s.checkWithoutInheritance(list);
    

    如果你同时使用两个Lists,你会得到相同的输出:

    都失败了:

    List<B> list = new ArrayList<>();
    List<B> list2 = Arrays.asList(new B());
    s.checkWithoutInheritance(list2); 
    s.checkWithoutInheritance(list);
    

    两者都工作:

    s.checkWithoutInheritance(Arrays.asList(new B()));
    s.checkWithoutInheritance(new ArrayList<>());
    

    至于checkWithInheritance(final Collection&lt;? extends A&gt; s),它同时接受List&lt;A&gt;List&lt;B&gt;,这就是为什么你的checkWithInheritance 调用都通过编译。

    【讨论】:

      【解决方案2】:

      当你有方法时:

      void checkWithoutInheritance(final Collection<A> s);
      

      行:

      s.checkWithoutInheritance(Arrays.asList(new B()));
      

      工作正常,因为它与以下内容相同:

      List<A> list = Arrays.asList(new B());
      s.checkWithoutInheritance(list);
      

      但是,下面的代码:

      List<B> list = new ArrayList<B>();
      s.checkWithoutInheritance(list); // compiler error
      

      产生编译器错误,因为泛型are not covariantList&lt;B&gt; 不能分配给List&lt;A&gt;

      List<B> listb = new ArrayList<B>();
      List<A> lista = listb; // Incompatible types error, even though B extends A
      

      当你有方法时:

      void checkWithInheritance(final Collection<? extends A> s);
      

      &lt;? extends A&gt;wildcard放宽对变量s的限制,因此两者都有效:

      s.checkWithInheritance(new ArrayList<A>());
      s.checkWithInheritance(new ArrayList<B>());
      

      &lt;? extends A&gt; 适用于A 的列表和A 的子类型。

      【讨论】:

        【解决方案3】:
        List<B> list;
        

        这声明了一个列表变量,并保证该列表中的所有内容都可以转换为B(即BB 的子类,或null), to which you can only add things which can be cast toB`。

        private void checkWithoutInheritance(final Collection<A> s) {
        

        这声明了一个方法,接受一个集合参数,并保证该集合中的所有内容都可以转换为A,您只能向其中添加可以转换为A的内容。

        这意味着checkWithoutInheritance 可以这样做:

        s.add(new A());
        

        如果你能打电话

        checkWithoutInheritance(list);
        

        那么list 现在将包含A 的实例,它不能转换为B,违反了对list 内容的保证。

        因此,编译器不允许这样做。编译器并不关心您不要A 添加到s,因为您可以。它在安全方面犯了错误。


        另一方面:

        private void checkWithInheritance(final Collection<? extends A> s) {
        

        这声明了一个方法,接受一个集合参数,并保证该集合中的所有内容都可以转换为A的某个子类

        您不能在其中添加A,因为您不知道“某个子类”是指AB,还是完全其他的意思。

        因此,您不能在其方法体中写入s.add(new A());,因此将List&lt;B&gt; 传递给它是安全的。

        【讨论】:

          猜你喜欢
          • 2023-03-24
          • 1970-01-01
          • 2017-02-25
          • 1970-01-01
          • 1970-01-01
          • 2014-05-17
          • 1970-01-01
          • 2017-02-10
          • 2019-11-08
          相关资源
          最近更新 更多