Can I delude generics ?

Since java 1.5, we can use generics. It’s fantastic beacause we can now control very well the type that we manipulate !
Unfortunately, generics don’t ensure that your code will be type safe.
Ever since Java has respected backward compatibility, and with generics, code must provide support for older code. For this, Collections can be generic, or not.
Look at this, both lines are equivalent :

List l;
List<Object> l;

The question is : can I add an Integer to a List<String> ?
And the answer is … yes … WTF ?
Look at this :

public void m(List l) {
    l.add(42);
}
List<String> l = new ArrayList<String>();
m(l);

Here, we add an Integer into a List !
OMG It’s a disaster ! But … is it really a desaster ?
Yes, it’s dramatic.

Hum try to browse the list 😉

public void m(List l) {
    l.add(42);
}
List<String> l = new ArrayList<String>();
m(l);
for (Object o : l) ; // BOOM : ClassCastException

Oh … CallCastException oO ?
Yes, one more time, thanks to jad. What’s the code of ArrayList.get(int) ?

public E get(int index) {
    RangeCheck(index); // Oh my god, where is lowerCamelCase ?

    return (E) elementData[index];
}

Now we can see the cast which throws ClassCastException. The List really contains one Integer, but when we get the value, all we get is an exception …
If you’re totally mad, you can still use this trick to cast the List<String> to a List as follows :

for (Object o : (List) l); // Bye bye ClassCastException.

Even if you’ll never use this code (please promise me it), why does the cast solve the problem ?
The ArrayList.get(int) method always casts but without any explicit type given to ArrayList, Object is used. When you call the get method, before returning, the element is casted to Object.

We can easily examine the real implementation of generics (at compile time), and we’ll probably do it in a future post; stay tuned 😉

Advertisements

3 thoughts on “Can I delude generics ?

  1. The cast throwing the ClassCastException is not the one in ArrayList, but the one inserted by javac in the for loop. Javac notices an Iterable for loop on List and therefore inserts a (String) cast on the elements, regardless of the Object o declaration:

    Iterator iterator = l.iterator();
    while (iterator.hasNext()) {
    Object o = (String) iterator.next();
    }

    • It’s absolutely true, and reading the source code shows the actual get method implementation:

      public E get(int index) {
      rangeCheck(index);

      return elementData(index);
      }

      However jad allows the show us what’s executed at runtime whatever the source / compiler.
      Thank you for this very accurate comment though, I do appreciate!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s