Forcing Java generic parameters to be of the same type

前端 未结 2 1870
闹比i
闹比i 2021-01-04 07:54

How can a similar functionality be achieved without errors?

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

void foo(A a, X x) {
    a.f(x); // AN         


        
相关标签:
2条回答
  • 2021-01-04 08:15

    Keeping in mind the PECS rule, and given the way you are using X, you should be specifying as a lower instead of upper bound:

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

    This way no compiler errors are produced, and you have the most general signature applicable.

    0 讨论(0)
  • 2021-01-04 08:30

    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! :)

    0 讨论(0)
提交回复
热议问题