• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Tim Cooke
  • paul wheaton
  • Paul Clapham
  • Ron McLeod
Sheriffs:
  • Jeanne Boyarsky
  • Liutauras Vilda
Saloon Keepers:
  • Tim Holloway
  • Carey Brown
  • Roland Mueller
  • Piet Souris
Bartenders:

TypeCasting in Generics

 
Ranch Hand
Posts: 39
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Given this code

public class Test {
public static void append(List list)
{
list.add(42);
}
public static void main(String args[])
{
List<String> intList = new ArrayList<String>();
intList.add("Hello");
append(intList);
System.out.println(intList.get(1));//line 11
}

}

I get A class cast exception in line 11

but if reverse the situation by

->having intList of Generic Type Integer
->adding integer to it before calling append
->adding string to list inside append

then i get a valid output
Here is the reversed code that works.I want to know the explanation for it

//code with reversed situations

public class Test {
public static void append(List list)
{
list.add("Hello");
}
public static void main(String args[])
{
List<Integer> intList = new ArrayList<Integer>();
intList.add(10);
append(intList);
System.out.println(intList.get(1));
}

}
 
Ranch Hand
Posts: 78
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi,

to understand the difference between the two programs, you could use
a decompiler (jad, for example), to see what is really in the bytecode.

By doing this, you can see that there is a reason why these two programs
behave differently; in fact, there are different !

For the first code,
System.out.println(intList.get(1));
becomes in the bytecode :
System.out.println((String)intList.get(1));
hence, the ClassCastException (Integer cannot be cast in String).

But, for the second code,
System.out.println(intList.get(1));
becomes in the bytecode :
System.out.println(intList.get(1));
there is no cast added, and therefore, no runtime exception !

To understand why the two codes are not compiled the same way, we have to
understand how the java compiler handles type safety with generics. When a
method has a generics return type, the compiler adds an extra cast if
needed, that is to say, if the result is assigned in a variable of the
same generic type. But if the result is assigned in a Object variable, no
cast is added. You can see it in this example :
List<String> listString = new ArrayList<String>();
Object o = listString.get(1);
String s = listString.get(1);
becomes in the bytecode :
List listString = new ArrayList();
Object o = listString.get(1);
String s = (String)listString.get(1);
(remember that generics are removed in the bytecode, this is called type erasure).
We have made half the way to reach the solution.

The other key point to understand in this case is that System.out.println
has two overloaded versions, one taking an Object parameter, and one taking
a String parameter. Remember that the compiler choose the method to call at
compile time using the most specific type.

We have now all the tools to solve our case.

For the program one :
the compiler knows that intList.get(1) is a String object. It searches
among the overloaded versions of println which one it should call. There
is a version taking a String, so it selects this one. It means assigning
into a String variable, so a (String) cast is added.

For the program two :
the compiler knows that intList.get(1) is a Integer object. It searches
among the overloaded version of println which one it should call. The most
specific is the one taking an Object parameter, it takes this one. It means
assigning into an Object variable, so no cast is added.

The two programs have now two different bytecodes leading to two very
different behaviors.

Gilles

[ March 08, 2008: Message edited by: Gilles Marceau ]
[ March 08, 2008: Message edited by: Gilles Marceau ]
 
Ranch Hand
Posts: 49
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
thanks for a good answer
 
Consider Paul's rocket mass heater.
reply
    Bookmark Topic Watch Topic
  • New Topic