Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

about generic array creation in Java

Tags:

java

generics

just found a line of code that I do not quite understand.

List<String>[] stringLists = new List[1];

This line can pass the compilation on my AndroidStudio IDE though with warning. It seems to violate the basic rule of Object Oriented language: "the super class object can be instantiated with child class instance, but not vice versa."

String[] ss = new Object[1];  // won't compile

We know that List is super type of any generic List types, such as List<String> in this case. And as array is covariant, so I think List[] type is super of List<String>[] type. Why a List<String>[] can be instantiated with a List[]?

like image 704
cs2k Avatar asked Jan 18 '16 22:01

cs2k


2 Answers

I think the JLS, §4.8, "Raw Types" answers your actual question of why the assignment is valid:

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

It's for compatibility with pre-generics code. Generally if you're going for type-safety, you shouldn't use arrays of parameterised types at all, it would've been better if the author wrote:

List<List<String>> lists = new ArrayList<>();

Your assumption about a rule of type safety being violated is mistaken. You're saying that List is not a subtype of List<String>. However, in the Java type system, the answer to the question: "Is List a subtype of List<String>?" is neither "Yes", nor is it "No." It's "this question cannot be answered."

(It's also probably not correct to conflate "types" and "classes." There is only one List class, but List<String> and List<Object> are different types. Bonus: List<String> is not a subtype of List<Object>.)


To add a bit more detail about what's going on, the JLS explains what conversions are allowed in a variable assignment in §5.2, "Assignment Contexts". Notably, the list ends with:

If, after the conversions listed above have been applied, the resulting type is a raw type (§4.8), an unchecked conversion (§5.1.9) may then be applied.

The latter link to §5.1.9, "Unchecked Conversions", after some formalisms explaining what an unchecked conversion is, reiterates the rationale (emphasis mine):

Unchecked conversion is used to enable a smooth interoperation of legacy code, written before the introduction of generic types, with libraries that have undergone a conversion to use genericity (a process we call generification). In such circumstances (most notably, clients of the Collections Framework in java.util), legacy code uses raw types (e.g. Collection instead of Collection<String>). Expressions of raw types are passed as arguments to library methods that use parameterized versions of those same types as the types of their corresponding formal parameters.

Such calls cannot be shown to be statically safe under the type system using generics. Rejecting such calls would invalidate large bodies of existing code, and prevent them from using newer versions of the libraries. This in turn, would discourage library vendors from taking advantage of genericity. To prevent such an unwelcome turn of events, a raw type may be converted to an arbitrary invocation of the generic type declaration to which the raw type refers. While the conversion is unsound, it is tolerated as a concession to practicality. An unchecked warning is issued in such cases.

The official story is indeed that unchecked conversions from raw type to parameterised type were added to the language deliberately, despite being potentially unsafe, and are only marked with a compilation warning for compatibility reasons. (Java very much tries to ensure that code that compiled in version X never fails to compile or ceases to be useful in version X+1.)

like image 96
millimoose Avatar answered Nov 15 '22 16:11

millimoose


Generics in Java are just syntactic sugar in compilation time. In execution time, both lists are List<Object>

like image 33
Mario Avatar answered Nov 15 '22 17:11

Mario