2013-06-30 78 views
11

如何类似的功能没有错误来实现的?强制Java的泛型参数是同类型

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 <“非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>(); 
    } 
} 
+0

X是类还是类型参数? – Joni

回答

17

您可以力参数ERS做是同一类型以下:

// 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,并用它来执行该类AK类型参数必须匹配的x类型,foo第二个参数。

如果您愿意并且您的问题有意义,例如<T extends Bar> void foo(A<T> a, T x) {...}super,您甚至可以对<T>施加限制。你想这个,如果作为乔尼问上问题的评论,X实际上是一个类型,而不是一个类型参数:你会使用<T extends X> void foo(...)


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

方法容器.get()返回A<? extends K>一个实例。因此,您从.get()获取的实例的类型参数未完全指定。通常,返回这种非特定类型的设计并不是很好。对于约书亚布洛赫有效的Java和许多API和功能在Java中的作者的视频演示,展示了如何改善这样的API,检查:http://www.youtube.com/watch?v=V1vQf4qyMXg&feature=youtu.be&t=22m。正好25'36" ,约书亚·布洛克说:‘不要尝试使用它们[通配符类型]的返回值’,并解释说,他后来基本上,你不使用他们获得更多的灵活性,并且只是使API的用户很难处理它(你只是觉得这样做的效果......)

要解决这个问题,你可以简单地尝试将.get()的签名改为A<K> get(),这样容器类将是:

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

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

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

+0

但是如何使用? 'new Test().foo(a,x);'仍然返回错误: 类型A .Test中的方法foo(A ,T)不适用于参数(A ,X) – Evgeny

+0

您似乎将'Test'类定义为'A'的内部类,这不正是我在上面显示的内容。 –

+0

这似乎并不重要:现在的错误是'类型Test中的方法foo(A ,T)不适用于参数(A ,X)' – Evgeny

6

在牢记PECS rule,并给予您使用X的方式,你应该指定为而不是上限:

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

这样没有编译错误产生,并且您有最适合的一般签名。

+1

这不完全是问题所在:OP要求让'X'在'A a'和'X x'上成为*相同*类型。也许他确实需要你的回答,但这个问题应该改写。 –

+0

OP还询问“如何在没有错误的情况下实现类似的功能?” - 而Marko的答案就是这样。 – meriton

+0

@meriton的确如此。但是,这似乎有点太模糊,没有说明。 –