Re: A problem regarding generics
Kevin McMurtrie wrote:
It can lead to ClassCastException on nonexistent lines.
Lew wrote:
Kevin McMurtrie wrote:
Doh! I accidentally sent before I finished.
Generics can break inheritance. For example, the generics declaration
below demands that an override of put() take only a String as the key.
At the same time, HashMap without generics must take an Object as a key.
The compiler fixes this by adding a hidden method.
It adds an override method, but that's not so weird.
This compiles with a warning:
public class SnoopingMap<V> extends java.util.HashMap<String, V>
{
@Override
public V put(String key, V value)
{
System.out.println(key + " -> " + value);
return super.put(key, value);
}
public static void main (String args[])
{
SnoopingMap m= new SnoopingMap();
m.put(new Integer(4), new Integer(5));
}
}
But fails to run with an error on a bogus line number:
Exception in thread "main" java.lang.ClassCastException:
java.lang.Integer cannot be cast to java.lang.String
at SnoopingMap.put(SnoopingMap.java:1)
I see what you mean by "bogus" line number, though I would not have chosen
such an emotion-laden term myself.
at SnoopingMap.main(SnoopingMap.java:13)
And there's your real error.
The javap utility shows the hidden method:
public java.lang.Object put(java.lang.Object, java.lang.Object);
Signature: (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
Code:
0: aload_0
1: aload_1
2: checkcast #16; //class java/lang/String
5: aload_2
6: invokevirtual #17; //Method
put:(Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;
9: areturn
LineNumberTable:
line 1: 0
That translates to this code, which will not compile if you add it
yourself:
public Object put(Object key, Object value)
{
return put((String)key, value);
{
Adding that method by hand won't compile because it's erasure-equivalent to an
override and doesn't conform to the generics requirements, and you can't have
two erasure-equivalent methods in the same class.
They have to have some method for doing type erasure. From what you show it's
done by creating an override that does the class cast that you would have to
have done by hand in pre-generics times.
This does illustrate perfectly why you should avoid raw types - it defeats the
purpose of generics and leads to ClassCastException to use them.
--
Lew