我有以下课程:
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.:)
来自http://download.oracle.com/javase/tutorial/extra/generics/wildcards.html:
像往常一样,为使用通配符的灵活性付出了代价.这个价格是现在写入[基于通配符的容器]是非法的.例如,这是不允许的:
Run Code Online (Sandbox Code Playgroud)public void addRectangle(List<? extends Shape> shapes) { shapes.add(0, new Rectangle()); // Compile-time error! }您应该能够弄清楚为什么不允许上面的代码.第二个参数的类型
shapes.add()是? extends Shape- 一个未知的子类型Shape.由于我们不知道它是什么类型,我们不知道它是否是超类型Rectangle; 它可能是也可能不是这样的超类型,所以通过Rectangle那里是不安全的.