另一个java泛型问题

Cha*_*bel 6 java generics

我有以下课程:

interface Able{/* ... */}
class A implements Able{/* ... */}
Run Code Online (Sandbox Code Playgroud)

我有

Map<String,? extends Able> as;
as = new HashMap<String, A>();
Run Code Online (Sandbox Code Playgroud)

为什么以下会导致错误:

as.put("a", new A());
Run Code Online (Sandbox Code Playgroud)

有任何想法吗?

Sni*_*las 17

对java泛型的引用很好(jdk站点).

事实上,@ Oli_Charlesworth给出了一个很好的答案,但也许这个更完整.

在一个Collection<? extends Able>你不能插入任何正确的东西.

如果你有

class A implements Able {...}
Run Code Online (Sandbox Code Playgroud)

class B implement Able {...}
Run Code Online (Sandbox Code Playgroud)

然后,Collection<? extends Able>是两者的超级类型:

Collection<A>
Collection<B>
Run Code Online (Sandbox Code Playgroud)

因此,写一些声明是合法的

//Code snippet 01
Collection< ? extends Able > list;
Collection<A> listA;
Collection<B> listB;
list = listA;
list = listB;
Run Code Online (Sandbox Code Playgroud)

这确实是Collection<? extends Able>存在通配符的原因.

但是,事情变得越来越有趣:

在a中,Collection<A>您只能插入A(包括子类)的对象.同样的Collection<B>.在这两者中你都无法添加正义的东西Able.例如 :

//Code snippet 02
listA.add( new A() );  //valid at compile-time
listA.add( new B() );  //not valid at compile-time
listB.add( new B() );  //valid at compile-time
listB.add( new A() );  //not valid at compile-time
Run Code Online (Sandbox Code Playgroud)

因此,如果您对我们所看到的内容进行分组code snippets 01 & 02,您将理解编译器绝对不可能接受如下语句:

Collection< ? extends Able > list;
list.add( new A() );         //not allowed, will work only if list is List<A>
list.add( new B() );         //not allowed, will work only if list is List<B>
Run Code Online (Sandbox Code Playgroud)

所以是的,超级类型Collection< ? extends Able >不接受添加任何东西.更一般的类型提供了子类型的功能,因此,子类型的功能较少.在这里,我们失去了添加A对象和B对象的能力.这些功能将在层次结构中稍后发生......甚至意味着我们无法在超类中添加任何内容Collection< ? extends Able >

补充说明:

此外,请注意,Collection<Able>您可以添加任何你想要的东西:

Collection< Able > list;
list.add( new A() );         //valid
list.add( new B() );         //valid
Run Code Online (Sandbox Code Playgroud)

但是,Collection<Able>不是Collection<A>和超级的Collection<B>.与任何继承关系一样,这意味着子类可以执行超类可以执行的任何操作,因为继承是特化.因此,这意味着我们可以将A对象和B对象添加到两个子类中Collection<A>,Collection<B>而事实并非如此.因为它不是一个你不能拥有的超类:

Collection<Able> list;
Collection<A> listA;
Collection<B> listB;
list = listA;  //not valid because there is no inheritance hierarchy
list = listB;  //not valid because there is no inheritance hierarchy
Run Code Online (Sandbox Code Playgroud)

请注意,继承是一种超级联系(泛化/专门化),而集合定义了一个meronimic关系(容器/容器).将它们两者正式结合起来是一件令人头疼的问题,尽管人类模糊的生物很容易使用它,例如在法语词汇中:synecdocque.:)


Oli*_*rth 8

来自http://download.oracle.com/javase/tutorial/extra/generics/wildcards.html:

像往常一样,为使用通配符的灵活性付出了代价.这个价格是现在写入[基于通配符的容器]是非法的.例如,这是不允许的:

public void addRectangle(List<? extends Shape> shapes) {
    shapes.add(0, new Rectangle()); // Compile-time error!
}
Run Code Online (Sandbox Code Playgroud)

您应该能够弄清楚为什么不允许上面的代码.第二个参数的类型 shapes.add()? extends Shape- 一个未知的子类型Shape.由于我们不知道它是什么类型,我们不知道它是否是超类型 Rectangle; 它可能是也可能不是这样的超类型,所以通过Rectangle那里是不安全的.