Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bounded Type Parameters casting issue

Tags:

java

generics

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

like image 723
sockeqwe Avatar asked Dec 28 '15 13:12

sockeqwe


People also ask

What are bounded type parameters?

There may be times when you want to restrict the types that can be used as type arguments in a parameterized type. For example, a method that operates on numbers might only want to accept instances of Number or its subclasses. This is what bounded type parameters are for.

What are bounded type parameters in generic?

Whenever you want to restrict the type parameter to subtypes of a particular class you can use the bounded type parameter. If you just specify a type (class) as bounded parameter, only sub types of that particular class are accepted by the current generic class. These are known as bounded-types in generics in Java.

Is it possible to declared a multiple bounded type parameter?

Multiple BoundsBounded type parameters can be used with methods as well as classes and interfaces. Java Generics supports multiple bounds also, i.e., In this case, A can be an interface or class. If A is class, then B and C should be interfaces. We can't have more than one class in multiple bounds.

What is the difference between upper bounded wildcards and bounded type parameters?

What is the difference between a wildcard bound and a type parameter bound? A wildcard can have only one bound, while a type parameter can have several bounds. A wildcard can have a lower or an upper bound, while there is no such thing as a lower bound for a type parameter.


1 Answers

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.

like image 96
Erwin Bolwidt Avatar answered Oct 13 '22 15:10

Erwin Bolwidt