Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does Eclipse Compiler lose fixed type parameter?

I struggled to find a proper title for this question because the phenomenon I observed is very strange. Hence I skip explaining my problem literally and instead show you some (hopefully) self-describing code. Consider the following parameterized class:

public class GenericOptional<T> {

    public GenericOptional(T someValue) {}

    public T getValue() { return null; }

    public Optional<String> getOptionalString() { return Optional.empty(); }
}

What I like to emphasize is that the return type Optional<String> of the method getOptionalString() does not depend on the type-parameter T.

Now have a look at the following code, which gets compiled inside Eclipse Luna 4.4.2 using Java 8u45:

public static void main(String[] args) {
    Object obj = new GenericOptional<>(Boolean.TRUE);
    GenericOptional go = (GenericOptional) obj;
    Optional os = go.getOptionalString();
}

The local variable os has the type Optional without the type-parameter String! The Eclipse compiler has lost the information about the fixed type-parameter. Does anyone know why?

Now look at a second code example:

public static void main(String[] args) {
    Object obj = new GenericOptional<>(Boolean.TRUE);
    GenericOptional<?> go = (GenericOptional) obj;
    Optional<String> os = go.getOptionalString();
}

By declaring the local variable go as GenericOptional<?> the return type of the method getOptionalString() now is Optional<String> as expected.

May anyone explain this behavior?

like image 347
Harmlezz Avatar asked Jun 24 '15 06:06

Harmlezz


1 Answers

You are facing the behavior of raw types. When you are using a raw type, Generics are effectively turned off completely, regardless of whether there is a connection between the generic signature of the member and the type parameter of the class.

The reasoning behind this is that raw types are a feature for backward compatibility with pre-Generics code only. So either you have Generics or your don’t.

If the Generic method does not depend on the actual type parameter of the class, the problem is easy to fix:

GenericOptional<?> go = (GenericOptional<?>) obj;
Optional<String> os = go.getOptionalString();

Using <?> implies “I don’t know the actual type parameter and I don’t care but I’m using Generic type checking”.

like image 189
Holger Avatar answered Oct 18 '22 09:10

Holger