Odd compilation with shared classes and lists

So, I came across a strange compilation error when using a generic class that has a List attribute (either Map or Set, etc.).

A compilation error occurs when trying to iterate (using foreach) List:

Sample.java:11: error: incompatible types for (String string : s.getStringList()) { required: String found: Object 

Just to be clear, I know there is an easy way around the problem, but I want to understand what is wrong with the code

Below is the sample I created:

 import java.util.List; public class Sample<T> { public List<String> stringList; public static void main(String[] args) { Sample s = new Sample(); // Why this doesn't work? for (String string : s.getStringList()) { } // Why does both of the following work? List<String> newList = s.getStringList(); Sample<Object> s2 = new Sample<>(); for (String string : s2.getStringList()) { } } public List<String> getStringList() { return stringList; } } 
+7
java generics type-erasure
source share
2 answers

These lines

 Sample s = new Sample(); // Why this doesn't work? for (String string : s.getStringList()) { } 

do not work because you are using a raw form of the Sample class. When you use an unprocessed class form, all generics in the class, even unrelated generics, have type erasure. This means that getStringList now just returns a List from Object s, and not a List<String> from String s.

This part of Java was introduced using Generics in Java 1.5, so the old version of the classes that now use generics will be backward compatible. Thus, something that iterates over a List that used Object before can still use Object using the raw form of the List .

JLS section 4.8 deals with raw types:

More precisely, the type raw is defined as one of:

  • The type of link that is formed by accepting the name of the declaration of the type type without a list of arguments of the accompanying type.

and

The type of constructor (ยง8.8), the instance method (ยง8.4, clause 9.4) or the non-static field (ยง8.3) of the raw type C that is not inherited from its superclasses or superinterfaces is the original type, corresponding to erasing its type in the general declaration, corresponding to C.

(my accent)

Justification:

The use of raw types is allowed only as a concession to the compatibility of legacy code. Using raw types in code written after introducing generics into the Java programming language is strongly discouraged. It is possible that future versions of the Java programming language will prohibit the use of raw types.

+7
source share

The raw Sample type is used, and therefore the compiler assumes that you do not need generic types, even if the variables are not declared as raw types inside this object. This is a strange rule, but it is. You should not use raw types if you like generics. Once you use a raw type, all its members are also perceived by the compiler as raw.

+3
source share

All Articles