Timofey Gorshkov
Timofey Gorshkov

Reputation: 5125

Misunderstanding of class of returned instance from generic method of class called from subclass instance in Java

Example:

interface S {}

interface SS extends S {}

abstract class A<T extends S> {
    T get() {…}
}

abstract class B<BT extends SS> extends A<BT> {}

Why does ((B)someInstanceOfB).get() return an object of type S (and we should cast it to SS manually), when the compiler could determine that returned object is at least of type SS?

Why doesn't the compiler make implicit class cast to have clearer code? The code is of version 1.5+ and this is not secret for compiler. (Solved)

Update: Why doesn't the compiler compile B class as it implicitly has method BT get() { return super.get(); } ?

Is this problem solved in Java 1.7+?

Upvotes: 2

Views: 83

Answers (2)

Joachim Sauer
Joachim Sauer

Reputation: 308011

By casting to B you're using a raw type.

Using a raw type removes all generic information from the object, no matter where it is.

That means that for the raw type B the get method looks like it is returning a S (because that's the erasure (i.e. the actual type used at runtime) of the type parameter T).

To avoid this, never use raw types! They are meant exclusively for backwards compatibility and interaction with legacy code.

Cast to B<? extends SS> instead.

And no: this problem will probably never be "solved" in any future version of Java, as it's non-existing when you use generics correctly.

Regarding Update: no, B does not have a method BT get(). It has a method T get() where T is bound to the type parameter BT which has a lower bound SS. But since all generic type information is discarded when you use a raw type, T will still fall back to the original erasure, which is S.

The rule is quite simple and basically says "when you use a raw type it acts as if the class has no generics at all". The implications, however, are not always obvious, as in this case.

Upvotes: 4

sp00m
sp00m

Reputation: 48807

You didn't parameterize your instance of B.

Let's say you have the class C implementing SS:

Then, new B<C>().get(); would return an object of type C.

On the new B().get(); line, your IDE must have told you "B is a raw type. References to generic type B should be parameterized.".

Upvotes: 1

Related Questions