用“超级”关键字绑定generics
为什么我只能使用super通配符而不是types参数? 
 例如,在Collection接口中,为什么toArray方法不是这样写的 
 interface Collection<T>{ <S super T> S[] toArray(S[] a); } 
	
  super绑定一个命名的types参数(例如<S super T> )而不是通配符(例如<? super T> )是非法的,因为即使允许,它也不会做你想做的事情,因为由于Object是所有引用types的终极super ,而且一切都是Object , 实际上没有界限 。 
 在你的具体例子中,因为任何引用types的数组都是一个Object[] (通过Java数组协variables),所以它可以用作<S super T> S[] toArray(S[] a)绑定是合法的)在编译时,它不会阻止在运行时的ArrayStoreException 。 
你试图build议的是:
 List<Integer> integerList; 
 并给出了这个假设 super绑定到toArray : 
 <S super T> S[] toArray(S[] a) // hypothetical! currently illegal in Java 
编译器应该只允许编译以下内容:
 integerList.toArray(new Integer[0]) // works fine! integerList.toArray(new Number[0]) // works fine! integerList.toArray(new Object[0]) // works fine! 
 并没有其他数组types的参数(因为Integer只有3种typessuper )。 也就是说,你正试图阻止编译: 
 integerList.toArray(new String[0]) // trying to prevent this from compiling 
 因为根据你的论点, String不是Integer的super 。  但是 , Object是Integer的super类,而String[]是Object[] ,所以编译器仍然会让上面的代码编译,即使假设你可以做<S super T> ! 
 所以下面的代码仍然可以编译 (就像现在这样),并且在运行时ArrayStoreException不能被任何使用genericstypes边界的编译时检查阻止: 
 integerList.toArray(new String[0]) // compiles fine! // throws ArrayStoreException at run-time 
generics和数组不混合,这是它显示的许多地方之一。
一个非数组的例子
再次说,你有这个generics方法声明:
 <T super Integer> void add(T number) // hypothetical! currently illegal in Java 
你有这些variables声明:
 Integer anInteger Number aNumber Object anObject String aString 
 你用<T super Integer> (如果它是合法的)的意图是它应该允许add(anInteger)和add(aNumber) ,当然也add(anObject) ,但不能add(aString) 。 那么, String是一个Object ,所以add(aString)仍然可以编译。 
也可以看看
-   Java教程/generics
- 分型
- 通配符更有趣
 
相关问题
关于genericsinput规则:
-   任何简单的方法来解释为什么我不能做的List<Animal> animals = new ArrayList<Dog>()?
- javagenerics(不)协方差
-   什么是原始types,为什么我们不应该使用它?
-  介绍原始typesList与List<Object>不同的List<?>不同之处
 
-  介绍原始types
 关于使用super和extends : 
-  Java Generics: What is PECS?-  从有效的Java第2版 :“生产者extends消费者super”
 
-  从有效的Java第2版 :“生产者
-   Javagenerics中的super和extends什么区别?
-   <E extends Number>和<Number>之间有什么区别?
-   我如何添加到List<? extends Number>List<? extends Number>数据结构? (你不能!)
由于没有人提供满意的答案,正确的答案似乎是“由于Java语言不足”。
polygenelubricants提供了有关java数组协变的坏事情的好概述,这本身就是一个可怕的特性。 考虑下面的代码片段:
 String[] strings = new String[1]; Object[] objects = strings; objects[0] = 0; 
这显然是错误的代码编译而不诉诸任何“超”构造,所以数组协变不应该被用作一个参数。
 现在,在这里我有一个非常有效的代码需要super命名的types参数的例子: 
 class Nullable<A> { private A value; // Does not compile!! public <B super A> B withDefault(B defaultValue) { return value == null ? defaultValue : value; } } 
可能支持一些不错的用法:
 Nullable<Integer> intOrNull = ...; Integer i = intOrNull.withDefault(8); Number n = intOrNull.withDefault(3.5); Object o = intOrNull.withDefault("What's so bad about a String here?"); 
 后面的代码片段不能编译,如果我完全删除B ,所以B确实是需要的。 
 请注意,我试图实现的function很容易获得,如果我颠倒types参数声明的顺序,从而更改super约束extends 。 但是,只有将该方法重写为静态方法才有可能: 
 // This one actually works and I use it. public static <B, A extends B> B withDefault(Nullable<A> nullable, B defaultValue) { ... } 
 关键是,这种Java语言的限制确实限制了一些可能的有用function,并可能需要丑陋的解决方法。 我想知道如果我们需要withDefault为虚拟会发生什么。 
 现在,为了和polygenelubricants所说的相关联,我们在这里使用B而不是限制作为defaultValue传递的对象的types(请参阅示例中使用的String),而是限制调用者对我们返回的对象的期望。 作为一个简单的规则,您使用的extendstypes是您所需要的types,并且super您提供的types。 
您的问题的“官方”答案可以在Sun / Oracle错误报告中find 。
BT2:评估
看到
http://lampwww.epfl.ch/~odersky/ftp/local-ti.ps
特别是第3节和第9页的最后一段。在子types约束的两侧都接受typesvariables可以产生一组没有单一最佳解的types方程; 因此,types推断不能使用任何现有的标准algorithm来完成。 这就是为什么typesvariables只有“扩展”范围。
另一方面,通配符不必被推断,所以不需要这个约束。
@ ###。### 2004-05-25
是; 关键是通配符,即使被捕获,也只是用作推理过程的input; 没有什么(只)下限需要推断作为结果。
@ ###。### 2004-05-26
我看到了这个问题。 但是我不认为与推理期间通配符的下限有什么不同,例如:
名单<? 超级号码>;
布尔b;
…
s = b? s:s;目前,我们推断List <X>其中X扩展了Object作为条件expression式的types,这意味着该赋值是非法的。
@ ###。### 2004-05-26
可悲的是,谈话结束了。 (现在是死的)链接用来指向的文件是GJ的推断types实例 。 从最后一页看一眼,可以归结为:如果允许下限,则types推断可能产生多种解决scheme,但都不是主要的 。
假设我们有:
- 
基本classA> B> C和D class A{ void methodA(){} }; class B extends A{ void methodB(){} } class C extends B{ void methodC(){} } class D { void methodD(){} }
- 
工作包装类 interface Job<T> { void exec(T t); } class JobOnA implements Job<A>{ @Override public void exec(A a) { a.methodA(); } } class JobOnB implements Job<B>{ @Override public void exec(B b) { b.methodB(); } } class JobOnC implements Job<C>{ @Override public void exec(C c) { c.methodC(); } } class JobOnD implements Job<D>{ @Override public void exec(D d) { d.methodD(); } }
- 
和一个经理类与4种不同的方法来执行对象的工作 class Manager<T>{ final T t; Manager(T t){ this.t=t; } public void execute1(Job<T> job){ job.exec(t); } public <U> void execute2(Job<U> job){ U u= (U) t; //not safe job.exec(u); } public <U extends T> void execute3(Job<U> job){ U u= (U) t; //not safe job.exec(u); } //desired feature, not compiled for now public <U super T> void execute4(Job<U> job){ U u= (U) t; //safe job.exec(u); } }
- 
与使用 void usage(){ B b = new B(); Manager<B> managerB = new Manager<>(b); //TOO STRICT managerB.execute1(new JobOnA()); managerB.execute1(new JobOnB()); //compiled managerB.execute1(new JobOnC()); managerB.execute1(new JobOnD()); //TOO MUCH FREEDOM managerB.execute2(new JobOnA()); //compiled managerB.execute2(new JobOnB()); //compiled managerB.execute2(new JobOnC()); //compiled !! managerB.execute2(new JobOnD()); //compiled !! //NOT ADEQUATE RESTRICTIONS managerB.execute3(new JobOnA()); managerB.execute3(new JobOnB()); //compiled managerB.execute3(new JobOnC()); //compiled !! managerB.execute3(new JobOnD()); //SHOULD BE managerB.execute4(new JobOnA()); //compiled managerB.execute4(new JobOnB()); //compiled managerB.execute4(new JobOnC()); managerB.execute4(new JobOnD()); }
现在有什么build议如何实现execute4?
==========编辑=======
  public void execute4(Job<? super T> job){ job.exec( t); } 
谢谢大家 :)
==========编辑==========
  private <U> void execute2(Job<U> job){ U u= (U) t; //now it's safe job.exec(u); } public void execute4(Job<? super T> job){ execute2(job); } 
更好,任何代码与U内的execute2
超级U型变成了命名!
有趣的讨论:)