6

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?

Harmlezz
  • 7,972
  • 27
  • 35

2 Answers2

4

It's not about Eclipse or anything, but about raw types.

Let's review this snippet:

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

Here, you're creating a raw instance of GenericOptional, which means that the type-parameter information will be completely turned off. So, instantiating a raw GenericOptional means that the instance will expose the methods as following:

public class GenericOptional {

    public GenericOptional(Object someValue) {}

    public Object getValue() { return null; }

    public Optional getOptionalString() { return Optional.empty(); }
}

However, if we now review the second snippet

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

we can see that you're making a generic instance of GenericOptional. Even it's type-parameter is <?>, the compiler will not turn-off caring about type-parameters, so the instance will expose the getOptionalString() method parameterized, like this:

public Optional<String> getOptionalString() { return Optional.empty(); }
Konstantin Yovkov
  • 62,134
  • 8
  • 100
  • 147
  • Thank you Kocko for the nice explanation. Please see the comment I added to Holger's answer why I tended to gave him the "most helpful" approval. Hope you are fine with this decision. – Harmlezz Jun 24 '15 at 08:49
4

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”.

Community
  • 1
  • 1
Holger
  • 285,553
  • 42
  • 434
  • 765
  • Thank you for the answer. Kocko gave the same answer and I do not know how to give you both the correct / best approval. Hence due to the fact that you answered the question first, even so you did not provided example code to support your explanation, I will give you the "most helpful" approval. If you think Kocko's answer is of more value to people who want to know how it works, let me no and I will transfer the "most helpful" approval to Kocko. – Harmlezz Jun 24 '15 at 08:48