如何在没有错误的情况下实现类似的功能?
class A<K> {
void f(K x) {}
}
void foo(A<? extends X> a, X x) {
a.f(x); // AN error: The method f(capture#1-of ? extends X) in the
// type A<capture#1-of ? extends X> is not applicable for the
// arguments (X)
}
我知道它发生是因为'a'可以是A&lt;“non-X”&gt;的实例,所以它的'f'不能接受X的实例作为参数,但我怎么能强迫参数属于同一类型?
这是更多代码:
测试类:
class Test {
<T> void foo(A<T> a, T x) {
a.f(x); // now it works!
}
}
在某些课程中:
Container<X> container;
public void test() {
X x = new X();
new Test().foo(container.get(), x);
}
这是容器类:
public class Container<K> {
A<? extends K> get() {
return new A<K>();
}
}
答案 0 :(得分:18)
您可以通过执行以下操作强制参数类型:
// the first class, A<K>:
class A<K> {
void f(K x) {}
}
// the second class, defining the method with generic type parameters
class Test {
<T> void foo(A<T> a, T x) {
a.f(x); // now it works!
}
}
// a third class, that uses the above two:
class Main {
public static void main(final String... args) {
final Test test = new Test();
final A<String> a = new A<>();
test.foo(a, "bar");
}
}
这样做:方法foo
定义泛型类型参数T
,并使用它来强制类K
的{{1}}类型参数必须与类型A
,x
的第二个参数。
如果您愿意,您甚至可以对foo
施加限制,例如<T>
或<T extends Bar> void foo(A<T> a, T x) {...}
。如果 Joni 在问题中的评论中询问,super
实际上是一个类型而不是类型参数,那么你会想要这样:你使用X
。
在您显示更多代码后,问题就变得清晰了。
容器的方法<T extends X> void foo(...)
返回.get()
的实例。因此,未完全指定从A<? extends K>
获取的实例的类型参数。通常,返回这种未指定类型的设计并不是很好。有关使用Effective Java的作者Joshua Bloch以及Java中的许多API和功能的视频演示,请展示如何改进此类API,请查看:http://www.youtube.com/watch?v=V1vQf4qyMXg&feature=youtu.be&t=22m。正好在25'36“,Joshua Bloch说”不要试图在返回值上使用它们[通配符类型]“,他后来解释说。基本上,你不会通过使用它们获得更多的灵活性,只是制作API的用户很难处理它(你只是觉得这样做的效果......)。
要修复,您只需尝试将.get()
的签名更改为.get()
,因此容器类将为:
A<K> get()
由于您确实知道public class Container<K> {
A<K> get() {
return new A<K>();
}
}
正在返回get()
的实例,因此没有理由使用较旧的签名:它只会让您丢失您已经知道的信息!
如果这仍然不起作用,你的问题可能在其他地方,你需要显示更多的代码......或者更好的是,还要问其他问题! :)
答案 1 :(得分:6)
请记住PECS rule,并且考虑到使用X的方式,您应该指定为 lower 而不是上限:
void foo(A<? super X> a, X x)
这样就不会产生编译器错误,并且您可以使用最常用的签名。