强制 Java 泛型参数具有相同的类型

2022-09-04 01:07:36

如何实现类似的功能而不会出错?

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>();
    }
}

答案 1

您可以通过执行以下操作来强制参数具有相同的类型

// 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");
  }
}

这样做是:该方法定义了一个泛型类型参数,并使用它来强制类的类型参数必须与 的类型匹配,的第二个参数。fooTKAxfoo

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


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

容器的方法返回 的实例。因此,未完全指定从中获取的实例的类型参数。通常,返回这种未指定的类型不是很好。有关 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()A<? extends K>.get()

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

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

由于您知道 返回 的实例,因此没有理由使用较旧的签名:它只会让您丢失您已经知道的信息!get()A<K>

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


答案 2

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

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

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


推荐