Question

As per my understanding the following generic function in java:

public static <T> T f(T x) {
   Integer[] arr = new Integer[4];
   T ret = (T) arr[2];
   return ret;
}

is compiled to the following form (as it is unbounded):

public static Object f(Object x) {
   Integer[] arr = new Integer[4];
   Object ret = (Object) arr[2];
   return ret;
}

However, when I run the following statement, the compiler is able to figure out the return value to be Integer type. How does the compiler figure it out?

Integer i = f(new Integer(4));

Shouldn't the function be written as following for the above statement to work?

  public static <T extends Integer> T f(T x) {
       Integer[] arr = new Integer[4];
       T ret = (T) arr[2];
       return ret;
    }
Was it helpful?

Solution

Generics use type erasure. That basically means that generics are nothing more than implicit casts so when you do:

List<Integer> ...

it's no different to a normal List and may contain Integers or anything really. You're just telling Java to cast get() to an Integer (and other things). The type simply isn't retained at runtime (mostly).

Arrays are different. Arrays are what's called covariant. That means their type is retained at runtime. So you can do:

List<Integer> list1 = new ArrayList<Integer>();
list2 = (List<String>)list1;
list2.add("hello");

which is perfectly legal and will compile and run. But:

Integer[] arr1 = new Integer[10];
String[] arr2 = (String[])arr1; // compiler error

But it gets more subtle than that too.

Integer[] arr1 = new Integer[10];
Object[] arr2 = (Object[])arr1;
arr2[5] = "hello"; // runtime error!

As to your function. When you write:

public static <T> T f(T x) {
  Integer[] arr = new Integer[4];
  T ret = (T) arr[2];
  return ret;
}

you're telling the compiler to derive T, being the argument type and the return type, from the argument. So when you pass in an Integer the return type is Integer. When you call:

Integer i = f(new Integer(4));

the compiler is simply following your instructions. The function does take and return an Object in compiled form but it just does this:

Integer i = (Integer)f(new Integer(4));

implicitly.

Just like the List example above there is nothing stopping you have f() return anything you like rather than what it's supposed to return based on the parameterized type.

OTHER TIPS

Somebody with more knowledge in this topic might jump in later, meanwhile my humble explanation is this:

What you say is right, generics have type erasure which means that generic information is not available at runtime. It is however available at compile time and that's how the compiler can figure out that you're mixing types.

Hope that helps!

In your example, the compiler figures that the return type is the same type as the parameter passed to the function, since they're both parameterized to type T, which is resolved to be Integer. When generating the bytecode, it then erases the type parameters information.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top