Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Combining Raw Types and Generic Methods

Here's a question, this first code listing compiles just fine (JDK 1.6 | JDK 1.7):

ArrayList<String> a = new ArrayList<String>(); String[] s = a.toArray(new String[0]); 

However, if I declare the List reference as a raw type:

ArrayList a = new ArrayList(); String[] s = a.toArray(new String[0]); 

I get a compiler error saying the String[] is required but Object[] was found.

This means my compiler is interpreting the generic method as returning Object[] despite of receiving a String[] as its argument.

I doubled-checked the toArray(myArray) method signature:

<T> T[] toArray(T[] a); 

Therefore it is a parameterized method whose type parameter <T> has no relation whatsoever with that of the List (i.e. <E>).

I have no idea how using a raw type here affects the evaluation of parameterized methods using independent type parameters.

  • Does anyone has any idea why this code does not compile?
  • Does anybody knows any reference where this behavior is documented?
like image 642
Edwin Dalorzo Avatar asked Jun 13 '12 03:06

Edwin Dalorzo


People also ask

Why don't we just use Object as the parameterized type for our generic classes?

Answer is Object is superclass of all objects and can represent any user defined object. Since all primitives doesn't inherit from "Object" so we can't use it as a generic type.

What is a raw type and why is it useful?

A "raw type" is the use of a generic class without specifying a type argument(s) for its parameterized type(s), e.g. using List instead of List<String> . When generics were introduced into Java, several classes were updated to use generics.

What is a generic method and when should it be used?

Generic methods allow type parameters to be used to express dependencies among the types of one or more arguments to a method and/or its return type. If there isn't such a dependency, a generic method should not be used. It is possible to use both generic methods and wildcards in tandem.

Can generic types be primitive?

Generic type arguments are constrained to extend Object , meaning that they are not compatible with primitive instantiations unless boxing is used, undermining performance.


2 Answers

It's not exactly what you'd expect, but if you refer to a generic class in raw form, you lose the ability to use generics in any way for instance members. It's not restricted to generic methods either, check out this:

 public class MyContainer<T> {       public List<String> strings() {          return Arrays.asList("a", "b");      }  }   MyContainer container = new MyContainer<Integer>();  List<String> strings = container.strings(); //gives unchecked warning! 

This is the relevant part of the JLS (4.8):

The type of a constructor (§8.8), instance method (§8.4, §9.4), or non-static field (§8.3) M of a raw type C that is not inherited from its superclasses or superinterfaces is the raw type that corresponds to the erasure of its type in the generic declaration corresponding to C.

like image 53
Mark Peters Avatar answered Sep 19 '22 12:09

Mark Peters


When you don't use generics compiler treats it as a raw type and hence every generic type becomes Object and so you cannot pass String[] because it needs Object[]
So here is the deal - If you use

List l = new ArrayList<String>(); 

You are using raw type and all its instance members are replaced by its erasure counterparts. In particular each parameterized type appearing in an instance method declaration is replaced with its raw counterpart. See JLS 4.8 for details.

like image 42
Premraj Avatar answered Sep 18 '22 12:09

Premraj