moh*_*nof 55 java generics language-design super
为什么我super只能使用通配符而不使用类型参数?
例如,在Collection界面中,为什么toArray方法不是这样写的
interface Collection<T>{
<S super T> S[] toArray(S[] a);
}
Run Code Online (Sandbox Code Playgroud)
pol*_*nts 47
super绑定一个命名类型参数(例如<S super T>)而不是通配符(例如<? super T>)是ILLEGAL,因为即使它被允许,它也不会做你希望它会做的事情,因为因为它Object是super所有引用类型的终极,而且一切都是Object,实际上没有约束力.
在您的具体示例中,由于任何引用类型数组都是Object[](通过Java数组协方差),因此它可以<S super T> S[] toArray(S[] a)在编译时用作参数(如果此类绑定是合法的),并且它不会ArrayStoreException在运行时阻止 - 时间.
你要提出的建议是:
List<Integer> integerList;
Run Code Online (Sandbox Code Playgroud)
鉴于这个假设的 super界限toArray:
<S super T> S[] toArray(S[] a) // hypothetical! currently illegal in Java
Run Code Online (Sandbox Code Playgroud)
编译器应该只允许以下编译:
integerList.toArray(new Integer[0]) // works fine!
integerList.toArray(new Number[0]) // works fine!
integerList.toArray(new Object[0]) // works fine!
Run Code Online (Sandbox Code Playgroud)
并且没有其他数组类型参数(因为Integer只有这3种类型super).也就是说,您正在尝试阻止编译:
integerList.toArray(new String[0]) // trying to prevent this from compiling
Run Code Online (Sandbox Code Playgroud)
因为,你的说法,String是没有super的Integer.但是,Object是super的Integer,并且String[]是一个Object[],所以编译器仍然将让上面的编译,即使假设你能做到<S super T>!
因此,以下内容仍将编译(就像它们现在的方式一样),并且ArrayStoreException在运行时无法通过使用泛型类型边界的任何编译时检查来阻止:
integerList.toArray(new String[0]) // compiles fine!
// throws ArrayStoreException at run-time
Run Code Online (Sandbox Code Playgroud)
泛型和数组不混合,这是它显示的许多地方之一.
再说一次,假设你有这个泛型方法声明:
<T super Integer> void add(T number) // hypothetical! currently illegal in Java
Run Code Online (Sandbox Code Playgroud)
你有这些变量声明:
Integer anInteger
Number aNumber
Object anObject
String aString
Run Code Online (Sandbox Code Playgroud)
你的意图<T super Integer>(如果它是合法的)是它应该允许add(anInteger),add(aNumber)当然add(anObject),但不是add(aString).嗯,String是一个Object,所以add(aString)仍然会编译.
关于泛型类型规则:
List<Animal> animals = new ArrayList<Dog>()?List是从不同的List<Object>是从一不同的List<?>使用super和extends:
Java Generics: What is PECS?
extends消费者super"super和之间有什么区别extends<E extends Number>和之间有什么区别<Number>?List<? extends Number>数据结构?(你不能!)Rot*_*sor 33
由于没有人提供令人满意的答案,正确答案似乎是"没有充分理由".
polygenelubricants很好地概述了java数组协方差所发生的坏事,这本身就是一个可怕的特征.请考虑以下代码片段:
String[] strings = new String[1];
Object[] objects = strings;
objects[0] = 0;
Run Code Online (Sandbox Code Playgroud)
这显然错误的代码编译而不诉诸任何"超级"构造,因此不应将数组协方差用作参数.
现在,我super在命名类型参数中有一个完全有效的代码示例:
class Nullable<A> {
private A value;
// Does not compile!!
public <B super A> B withDefault(B defaultValue) {
return value == null ? defaultValue : value;
}
}
Run Code Online (Sandbox Code Playgroud)
可能支持一些不错的用法:
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?");
Run Code Online (Sandbox Code Playgroud)
如果我B完全删除后面的代码片段就不会编译,所以B确实需要.
请注意,如果我反转类型参数声明的顺序,那么我正在尝试实现的功能很容易获得,从而将super约束更改为extends.但是,这只有在我将方法重写为静态方法时才有可能:
// This one actually works and I use it.
public static <B, A extends B> B withDefault(Nullable<A> nullable, B defaultValue) { ... }
Run Code Online (Sandbox Code Playgroud)
关键是这种Java语言限制确实限制了一些其他可能有用的功能,可能需要丑陋的解决方法.我想知道如果我们需要withDefault虚拟会发生什么.
现在,为了与polygenelubricants所说的相关联,我们B在这里使用不限制传递的对象的类型defaultValue(参见示例中使用的String),而是限制调用者对我们返回的对象的期望.作为一个简单的规则,您可以使用extends您需要super的类型以及您提供的类型.
Ben*_*ulz 11
可以在Sun/Oracle错误报告中找到您的问题的"官方"答案.
BT2:评估
看到
http://lampwww.epfl.ch/~odersky/ftp/local-ti.ps
特别是第3节和第9页的最后一段.允许子类型约束两侧的类型变量可以产生一组没有单一最佳解的类型方程; 因此,使用任何现有的标准算法都无法进行类型推断.这就是类型变量只有"扩展"边界的原因.
另一方面,通配符不必推断,因此不需要这种约束.
@ ###.### 2004-05-25
是; 关键点在于,即使被捕获,通配符也仅用作推理过程的输入; 没有(仅)下限需要作为结果推断出来.
@ ###.### 2004-05-26
我看到了问题.但我不明白它与我们在推理过程中遇到的通配符下限问题有什么不同,例如:
名单<?超级数> s;
布尔b;
......
s = b?s:s;目前,我们推断List <X>,其中X扩展Object作为条件表达式的类型,这意味着赋值是非法的.
@ ###.### 2004-05-26
可悲的是,谈话在那里结束了.(现在死的)链接用于指向的论文是GJ的推断类型实例化.从浏览最后一页开始,它归结为:如果允许下限,则类型推断可能会产生多个解,其中没有一个是主要的.
| 归档时间: |
|
| 查看次数: |
11837 次 |
| 最近记录: |