Bounding generics with 'super' keyword
为什么我只能对通配符使用
例如,在
1 2 3 | interface Collection<T>{ <S super T> S[] toArray(S[] a); } |
在您的具体示例中,由于任何引用类型的数组都是EDCOX1×6(由Java数组协方差),因此它可以在编译时用作EDCOX1×7(如果这种绑定是合法的)的参数,并且它不会在运行时阻止EDCOX1×8的引用。
你想提出的建议是:
1 | List<Integer> integerList; |
假设
1 | <S super T> S[] toArray(S[] a) // hypothetical! currently illegal in Java |
编译器只允许编译以下内容:
1 2 3 |
而且没有其他数组类型参数(因为
1 |
因为,根据你的论点,
因此,以下仍然可以编译(就像现在一样),运行时的
1 2 |
泛型和数组不混合,这是它显示的众多地方之一。
非数组示例同样,假设您有这个泛型方法声明:
1 | <T super Integer> void add(T number) // hypothetical! currently illegal in Java |
您有这些变量声明:
你对
- Java教程/泛型
- 子类型
- 野猫游戏更有趣
相关问题
关于泛型类型规则:
- 有什么简单的方法来解释为什么我不能做
List ?animals = new ArrayList () - Java泛型(非)协方差
- 什么是原始类型,为什么不使用它?
- 解释原始类型
List 与List 的区别,后者与List> 不同。
- 解释原始类型
使用
Java Generics: What is PECS? - 从有效的Java第二版:"生产者EDCOX1,36,消费者EDCOX1,0"
- 在Java泛型中EDCOX1与0和EDCX1 36的区别是什么?
和 有什么区别?- 如何添加到
List extends Number> 数据结构中?(你不能!)
由于没有人给出令人满意的答案,正确的答案似乎是"没有充分的理由"。
多基因修饰剂提供了一个很好的概述与Java阵列协方差发生的坏事,这本身就是一个可怕的特性。考虑以下代码片段:
这显然是错误的代码在编译时没有使用任何"super"构造,因此数组协方差不应该用作参数。
现在,我有一个非常有效的代码示例,它要求在命名类型参数中使用
1 2 3 4 5 6 7 | class Nullable<A> { private A value; // Does not compile!! public <B super A> B withDefault(B defaultValue) { return value == null ? defaultValue : value; } } |
可能支持一些不错的用法:
1 2 3 4 |
如果完全删除
注意,如果我颠倒类型参数声明的顺序,从而将
1 2 | // This one actually works and I use it. public static <B, A extends B> B withDefault(Nullable<A> nullable, B defaultValue) { ... } |
问题在于,这种Java语言限制确实限制了一些其他可能有用的特性,并且可能需要难看的解决方案。我想知道如果我们需要
现在,为了与Polygene润滑剂所说的相关联,我们在这里使用
您问题的"官方"答案可以在Sun/Oracle错误报告中找到。
BT2:EVALUATION
See
http://lampwww.epfl.ch/~odersky/ftp/local-ti.ps
particularly section 3 and the last paragraph on page 9. Admitting
type variables on both sides of subtype constraints can result in a
set of type equations with no single best solution; consequently,
type inference cannot be done using any of the existing standard
algorithms. That is why type variables have only"extends" bounds.Wildcards, on the other hand, do not have to be inferred, so there
is no need for this constraint.@###.### 2004-05-25
Yes; the key point is that wildcards, even when captured, are only used
as inputs of the inference process; nothing with (only) a lower bound needs
to be inferred as a result.@###.### 2004-05-26
I see the problem. But I do not see how it is different from the problems
we have with lower bounds on wildcards during inference, e.g.:List super Number> s;
boolean b;
...
s = b ? s : s;Currently, we infer List
where X extends Object as the type of the
conditional expression, meaning that the assignment is illegal.@###.### 2004-05-26
可悲的是,谈话到此结束。文章中(现在死)链接用于点是推断类型实例化的GJ。从最后一页开始,它可以归结为:如果允许使用下限,类型推断可能会产生多个解,其中没有一个是主解。
假设我们有:
基本类A>B>C和D
1
2
3
4
5
6
7
8
9
10
11
12
13
14class A{
void methodA(){}
};
class B extends A{
void methodB(){}
}
class C extends B{
void methodC(){}
}
class D {
void methodD(){}
}作业包装类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30interface Job<T> {
void exec(T t);
}
class JobOnA implements Job<A>{
@Override
public void exec(A a) {
a.methodA();
}
}
class JobOnB implements Job{
@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种不同的方法在对象上执行作业
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25class 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);
}
}随着使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28void usage(){
B b = new B();
Manager 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());
}
有没有建议现在如何实现Execute4?
=====编辑时间:
1 2 3 | public void execute4(Job<? super T> job){ job.exec( t); } |
感谢大家:)
=======编辑时间======
1 2 3 4 5 6 7 | 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); } |
更好的是,任何在execute2中有u的代码
超级U型被命名!
有趣的讨论:)