问题描述
不,这个问题不是关于它们之间的区别吗? 和T; 这是关于我如何变成<? >参数命名为<T>。 考虑这个示例代码:
import java.io.Serializable;
class A<T extends Serializable> {
<S extends Serializable> void bar(S arg) { }
void bar2(T arg) { }
}
public class B {
A<? extends Serializable> myA = null;
<T extends Serializable> void foo(T arg) {
myA.bar(arg);
myA.bar2(arg);
}
}
我的问题是上面没有编译的事实; 对bar2()的调用给了我
The method bar2(capture#2-of ? extends Serializable) in the type
A<capture#2-of ? extends Serializable> is not applicable for the arguments (T)
我猜这个“原因”是myA是<? extends Serializable> ; 但B.foo中的T ......很好,一个名叫T; 而不是通配符?
“修复”这种方法的一种方法是使<T extends Serializable>为B类的类型参数...但这基本上与我对该类的其他用法冲突。 含义:我最终写下了B及其成员myA,这完全是因为我不想参数化B类。 所以,我开始只使用bar2()方法; 然后稍后添加了bar()......但这并没有真正帮助。
那么 - 有没有办法让我的班级B在我的示例代码中使用A.bar2()作为“预期”?
编辑:而且确切地说 - bar()方法对我没有帮助; 因为那里的“S”......与我在A班中真正使用的“T”不兼容。
1楼
你走到了尽头。
A<? extends Serializable> myA = ...;
所以myA
是A
的未知的东西。
它可以是A<String>
,或A<Integer>
或A<Banana>
。
你只是不知道。
让我们说这是一个A<Banana>
。
<T extends Serializable> void foo(T arg) {
所以foo()
接受任何可序列化的:String,Integer,Banana,Apple,等等。
假设它以Integer
作为参数调用。
myA.bar2(arg);
因此,基于上面的假设,虽然myA
是A<Banana>
,但它会调用bar2()
并将Integer作为参数。
编译器无法接受这一点:它显然不是类型安全的。
B
必须是通用的。
2楼
@JBNizet已经解释了为什么不能这样做。 这个答案旨在解释你可能有的选择(其中一个在你的问题中正确指出,但这不是唯一的选择)。
使B采用类型参数
class B<T extends Serializable> {
A<T> myA = null;
void foo(T arg) {
myA.bar(arg);
myA.bar2(arg);
}
}
使B从A延伸(如果B通过A的a-a测试)
class B extends A<String> {
public void foo(String arg) {
bar2(arg);
bar(1);
}
}
两个选项之间的区别在于:1) bar
和bar2
需要传递相同的类型,其中2) bar
和bar2
可以传递不同的类型,因为bar2
由为A
声明的类型参数绑定,其中bar
是由为方法声明的类型参数绑定。