sockeqwe
sockeqwe

Reputation: 15929

Bounded Type Parameters casting issue

I have a java interface like this

public interface MyInterface<T> {
  public <V extends T> V get(String key, Bundle bundle);
}

please note the <V extends T> type parameter of the method.

Then I have a class MyFoo implements MyInterface

class MyFoo implements MyInterface<Object> { // Object because can be any type

  @Override public <V> V get(String key, Bundle bundle) {
    return new Other();
  }
}

So when I now have a class like this:

class Bar {
   public Other other;

   public Other setOther(Other other);
}

Then I want to take MyFoo to set Other in a Bar instance:

MyFoo foo = new MyFoo();
Bar bar = new Bar();
bar.other = foo.get();

This works perfectly. Type can be determined by java generics. No additional cast is needed.

However, if I want to use bar.setOther() then the type can not be determined:

MyFoo foo = new MyFoo();
Bar bar = new Bar();
bar.setOther(foo.get()); // Fails

Then I get the following compile error:

error: incompatible types: Object cannot be converted to Other

I don't understand why this doesn't work for the bar.setOther( foo.get() ) method but works when accessing the field directly bar.other = foo.get()

Any idea how to solve that without adding an extra cast like bar.setOther( (Other) foo.get() )

Upvotes: 6

Views: 234

Answers (1)

Erwin Bolwidt
Erwin Bolwidt

Reputation: 31299

In an assignment, the Java compiler knows what return type to use for the method by looking at the type that it is being assigned to. So to answer your question

Any idea how to solve that without adding an extra cast like bar.setOther( (Other) foo.get() ) ?

This is a way in which you can do that:

Other value = foo.get();
bar.setOther(value);

There is another way, which looks worse but still doesn't have a cast:

bar.setOther(foo.<Other>get());

And a third alternative: switch to Java 8; in Java 8 you can just do bar.setOther(foo.get());.

For Java 7, the rules for this type inference are specified in JLS section 15.12.2.8:

If any of the method's type arguments were not inferred from the types of the actual arguments, they are now inferred as follows.

If the method result occurs in a context where it will be subject to assignment conversion (§5.2) to a type S, then [...]

A method result is subject to assignment conversion if it is used in an assignment expression.

  • Otherwise, the unresolved type arguments are inferred by invoking the procedure described in this section under the assumption that the method result was assigned to a variable of type Object.

If the unresolved type argument is used in a method whose result is not used in an assignment expression, then the type argument is interpreted as if the method result was assigned to a variable of type Object. So this means in this case that if the result of the get() method is not assigned to a variable, then the return type of the get() method is taken to be Object.

Upvotes: 3

Related Questions