Why does the Eclipse compiler lose a parameter of a fixed type?

I struggled to find the right name for this question, because the phenomenon that I observed is very strange. Therefore, I will skip the explanation of 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(); } } 

I would like to emphasize that the return type Optional<String> the getOptionalString() method is independent of the type parameter T

Now look at the following code that compiles 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 os local variable is of type Optional without a parameter of type String ! The Eclipse compiler has lost information about a fixed type parameter. Does anyone know why?

Now consider the second code example:

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

GenericOptional<?> declaring the local go variable as GenericOptional<?> , The return type of the getOptionalString() method will now be Optional<String> as expected.

Can someone explain this behavior?

+6
source share
2 answers

You have encountered the behavior of raw types . When you use a raw type, Generics are effectively disabled completely, regardless of whether there is a relationship between the common member signature and the type parameter of this class.

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

If the Generic method does not depend on the actual parameter of the class type, the problem can be easily fixed:

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

Using <?> Implies: "I don't know the actual type parameter, and I'm not interested, but I use generic type checking."

+4
source

This is not about Eclipse or anything else, but about raw types.

Check out this snippet:

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

Here you create a raw instance of GenericOptional , which means that the type parameter information will be completely disabled. So, creating an instance of raw GenericOptional means that the instance will expand the methods as follows:

 public class GenericOptional { public GenericOptional(Object someValue) {} public Object getValue() { return null; } public Optional getOptionalString() { return Optional.empty(); } } 

However, if we consider the second fragment

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

we see that you are making a generic instance of GenericOptional . Even this parameter of type <?> , The compiler is not disabled, taking care of the type parameters, therefore the instance will expose the getOptionalString() parameter to a parameter, for example:

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

Source: https://habr.com/ru/post/989657/


All Articles