13

如何在没有错误的情况下实现类似的功能?

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<"non-X"> 的实例,所以它的 '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>();
    }
}
4

2 回答 2

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类的类型参数A必须匹配 的类型x,即 的第二个参数foo

<T>如果您愿意,甚至可以对您的问题是否有意义,例如<T extends Bar> void foo(A<T> a, T x) {...}或 with施加限制super。如果正如Joni在问题中的评论中所问的那样,X它实际上是一种类型而不是类型参数,那么你会想要这个:你会使用<T extends X> void foo(...).


显示更多代码后,问题就变得清晰了。

容器的方法.get()返回一个A<? extends K>. 因此,您从中获取的实例的类型参数.get()没有完全指定。通常,返回这种未指定的类型并不是很好的设计。有关 Effective Java 和 Java 中的许多 API 和功能的作者 Joshua Bloch 的视频演示,展示了如何改进此类 API,请查看:http://www.youtube.com/watch?v=V1vQf4qyMXg&feature=youtu。贝&t=22m。正好在 25'36",Joshua Bloch 说“不要尝试在返回值上使用它们 [通配符类型]”,他稍后解释。基本上,使用它们不会获得更多的灵活性,只是让API 的用户很难处理它(你只是感觉到这样做的效果......)。

要修复,您可以简单地尝试更改 to 的签名.get()A<K> get()因此容器类将是:

public class Container<K> {
  A<K> get() {
    return new A<K>();
  }
}

既然你知道那get()是返回一个 的实例A<K>,没有理由使用旧签名:它只会让你丢失你已经知道的信息!

如果这仍然不起作用,您的问题可能在其他地方,您需要显示更多代码......或者更好的是,问其他问题!:)

于 2013-06-30T12:40:11.233 回答
6

请记住PECS 规则,并考虑到您使用 X 的方式,您应该指定为下限而不是上限:

void foo(A<? super X> a, X x)

这样就不会产生编译器错误,并且您拥有最通用的适用签名。

于 2013-06-30T12:45:54.100 回答