强制Java通用参数具有相同的类型 [英] Forcing Java generic parameters to be of the same type

查看:72
本文介绍了强制Java通用参数具有相同的类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

  class A< K> {
void f(K x){}
}

void foo(A< ;? extends X> a,X x){
a.f(x); //错误:在
//类型A<捕获#1中的方法f(捕获#1中的?扩展X)?扩展X>不适用于
//参数(X)
}

我知道它发生是因为'a'可以是A<non-X>的一个实例,所以它的'f'不能接受X的一个实例作为参数,但是我怎样才能强制参数是相同的类型?

以下是更多代码:

测试类:

  class Test {
< T> void foo(A< T> a,T x){
a.f(x); //现在它工作!


$ / code $ / pre

在某些课程中:

 容器< X>容器; 
public void test(){
X x = new X();
new Test()。foo(container.get(),x);
}

以下是容器类:

  public class Container< K> {
A <?延伸K> get(){
返回新的A< K>();



$ div $解析方案

你可以通过执行以下操作强制参数为相同类型:

  //第一个A< K>:
class A< K> {
void f(K x){}
}

//第二类,用泛型类型参数定义方法
class Test {
< T> void foo(A< T> a,T x){
a.f(x); //现在它工作!
}
}

//第三类,使用以上两个:
class Main {
public static void main(final String .. 。args){
final Test test = new Test();
final A< String> a = new A<>();
test.foo(a,bar);




$ b $ p
$ b

这个函数的作用是:方法 foo 定义了一个泛型类型参数 T ,并用它来强制执行 K A 的类型参数必须匹配 x 的类型, foo的第二个参数。



如果您愿意,甚至可以限制< T> 如果它对你的问题有意义,比如< T extends Bar> void foo(A a,T x){...} ,或者 super 。你会想要这样做,因为 Joni 在问题中提出了一个注释, X 实际上是一个类型而不是一个类型参数:使用< T extends X> void foo(...)






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



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

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

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

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



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

How can a similar functionality be achieved without errors?

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

I know that it happens because 'a' can be an instance of A<"non-X">, so its 'f' mustn't accept an instance of X as a parameter, but how can I force the parameters to be of the same type?

Here is more code:

Test class:

class Test {
   <T> void foo(A<T> a, T x) {
   a.f(x); // now it works!
 }
}

In some class:

Container<X> container;
public void test() {
    X x = new X();
    new Test().foo(container.get(), x);
}

Here's the container class:

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

解决方案

You can force the parameters to be of the same type by doing the following:

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

What this does is: the method foo defines a generic type parameter T and uses it to enforce that the K type parameter of the class A must match the type of x, the second parameter of foo.

You could even impose restrictions on <T> if you wish and if it makes sense for your problem, such as <T extends Bar> void foo(A<T> a, T x) {...}, or with super. You would want this if, as Joni asked on a comment in the question, X is actually a type and not a type parameter: you'd use <T extends X> void foo(...).


After you've shown more code, the problem becomes clear.

The method .get() of the container returns an instance of A<? extends K>. Therefore, the type parameter of the instance you obtain from .get() is not fully specified. Usually, it is not very good design to return such an unspecified type. For a video presentation with Joshua Bloch, the author of Effective Java and many APIs and features in Java, showing how to improve such an API, check this: http://www.youtube.com/watch?v=V1vQf4qyMXg&feature=youtu.be&t=22m. At exactly 25'36", Joshua Bloch says "don't try to use them [wildcard types] on return values", and he explains it later. Basically, you don't get any more flexibility by using them, and just makes it painfully hard for users of the API to deal with it (you just felt the effects of doing it...).

To fix, you could simply try to change the signature of .get() to A<K> get(), so the container class would be:

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

Since you do know that get() is returning an instance of A<K>, there's no reason to use the older signature: it simply makes you lose information you already know!

And if this still doesn't work, your problem might be somewhere else, and you'd need to show even more code... or better still, ask other questions! :)

这篇关于强制Java通用参数具有相同的类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆