java implement generic interface in an anonymous c

2020-08-11 10:23发布

问题:

Given the following interface,

 public interface Callback<T> {
    <K, V> T execute(Operation<K, V> operation) throws SomeException;
 }

How would I implement the interface in a new anonymous class where operation is of type Operation<String,String>

e.g, this doesn't compile:

 Callback<Boolean> callback = new Callback<Boolean>() {
        @Override
        public Boolean execute(Operation<String, String> operation) {
              return true;
        }
 };
 executor.execute(callback);

回答1:

the generics on the method are unrelated to the class generic parameters

you need to repeat them on the method for it to be correct, e.g.

Callback<Boolean> callback = new Callback<Boolean>() {
        @Override
        public <X,Y> Boolean execute(Operation<X, Y> operation) {

        }
};
executor.execute(callback);

In other words the interface requires an execute method that works on any Operation parameters.

If you want a callback that only works on specific parameters you need to make them part of the class signature, e.g.

 public interface Callback<T,K,V> {
    T execute(Operation<K, V> operation) throws SomeException;
 }

that would then let you do

Callback<Boolean,String,String> callback = new Callback<Boolean,String,String>() {
        @Override
        public Boolean execute(Operation<String, String> operation) {

        }
};
executor.execute(callback);

I cannot see a route to getting what you want... unless you start using the <? super K,? super V> or <? extends K,? extends V> forms which may restrict you too much.

Here is what your interface erases to

 public interface Callback<T> {
    T execute(Operation<Object, Object> operation) throws SomeException;
 }

then when you instantiate with T == Boolean we get

 public interface Callback {
    Boolean execute(Operation<Object, Object> operation) throws SomeException;
 }

which cannot be implemented by a

    Boolean execute(Operation<String, String> operation) throws SomeException;

method as the in parameters are narrower. You can widen in parameters and narrow out parameters but you cannot go the other way.

That explains why you can change the return type (out parameter) from Object to Boolean as anyone expecting an Object will be happy with a Boolean.

Conversely we cannot widen the return type as that would give a ClassCastException to anyone calling the method and acting on the result.

The method arguments (in parameters) can only be widened. Now it is somewhat complex for method arguments as Java sees different types as different methods, so you can legally have

public interface Callback<T> {
  T execute(Object key, Object value);
}

Callback<Boolean> cb = new Callback<Boolean> {
  @Override
  public Boolean execute(Object k, Object v) { ... }
  // not an @Override
  public Boolean execute(String k, String v) { ... }
}

because the second method has a different signature. But your Operation<X,Y> class gets erased to just the raw type irrespective of whether it is an Operation<String,String> or Operation<X,Y>

There is one thing you could do... but it gets messy!

public interface StringOperation extends Operation<String,String> {}

then you can do

Callback<Boolean> cb = new Callback<Boolean> {
  @Override
  public <K,V> Boolean execute(Operation<K,V> o) { ... }
  // not an @Override
  public Boolean execute(StringOperation o) { ... }
}

but keep in mind that the execute(Callback<?>) method will be calling <K,V> Boolean execute(Operation<K,V> o) and not Boolean execute(StringOperation o)



回答2:

Because the type parameter in your class name and the type parameter in the method are actually different You can do below.

   @Override
    public <K, V> Boolean execute(Operation<K, V> operation)
            throws SomeException {
        return false;
    }


标签: java generics