Type erasure- missing the point
Please treat me gently all you scary java pros!! Being so new to this, I am bound to use the wrong terminolgy so please be patient :) Throughout my post I have copied and pasted in examples from the tutorial pages- hope thats ok.
Basically I'm struggling with the whole type erasure thing. According to the tutorial on generics, defining the following class is not allowed:
publicclass MyClass<E>{
publicstaticvoid myMethod(Object item){
if (iteminstanceof E){//Compiler error
...
}
E item2 =new E();//Compiler error
E[] iArray =new E[10];//Compiler error
E obj = (E)new Object();//Unchecked cast warning
}
}
Now which aspect of using 'E' (the Type parameter) exactly is it that isn't allowed? I understand that if i created an instance of MyClass with an actual type argument e.g. MyClass<String>, type erasure strips it to the raw type at run time i.e. MyClass and therfore the <String> parameter is used only during compile time (I think).
As such, if the class was instead a class that implemented the List interface, for example 'MyList', MyList<String> would become List, and at runtime, there is apparently no way of finding out what 'sort of a list' it is unless you remove an object from the list and test it.
But I get confused because if instead you defined a class simliarly to the well known Box class that the generics tutorial defines surely you can just check to see what 'Type' the 't' variable represents which would infact tell you 'what sort of a box' it was.
publicclass Box<T>{
private T t;// T stands for "Type"
publicvoid add(T t){
this.t = t;
}
public T get(){
return t;
}
}
In fact I've tried it and I know it works; so at what point does type erasure stop you treating the 'Type paramaters' as temporary subs for the actual types and using them in methods, constructors and class definitions, because apparently this sort of thing is also fine:
publicstatic <E>void swap(List<E> a,int i,int j){
E tmp = a.get(i);
a.set(i, a.get(j));
a.set(j, tmp);
}
eh? in the top class declaration, you weren't allowed to create a new object like this :E item2 =new E();
and yet in the 'swap' method, you create an object of type E called temp.
Hope the question wasn't too waffly Oo
[3741 byte] By [
Kazeha] at [2007-11-27 11:26:42]

if my question just doesn't make sense please say so!
Kazeha at 2007-7-29 16:12:03 >

> Basically I'm struggling with the whole type erasure
> thing. According to the tutorial on generics,
> defining the following class is not allowed:
> public class MyClass<E> {
>public static void myMethod(Object item) {
>if (item instanceof E) { //Compiler error
Because instanceof is a runtime check. E erases to Object, which would of course make the conditional always true. So the compiler prevents you from doing it.
> E item2 = new E();//Compiler error
Because the compiler doesn't know what the actual type is, so can't call the constructor. The variable definition (left-hand side of assignment) is fine, it's the right-hand side that won't work.
> E obj = (E)new Object(); //Unchecked cast warning
Again, the cast is a runtime thing, and E erases to Object. The compiler allows this because there are conceivable cases where you'd want a cast -- in particular, where E erases to something other than Object. However, for clean code you should eliminate these warnings.
> But I get confused because if instead you defined a
> class simliarly to the well known Box class that the
> generics tutorial defines surely you can just check
> to see what 'Type' the 't' variable represents which
> would infact tell you 'what sort of a box' it was.
A runtime check? As in t.getClass()? Sure, but what benefit do you get from that?
> and yet in the 'swap' method, you create an object of
> type E called temp.
No, you're creating a variable called "temp". That variable is assigned a reference to an existing object in your List.
> > > public class MyClass<E> {
> >public static void myMethod(Object item) {
> >if (item instanceof E) { //Compiler error
>
> Because instanceof is a runtime check. E erases to
> Object, which would of course make the conditional
> always true. So the compiler prevents you from doing
> it.
Is that the reason why there is a compiler error here? If the condition of an if statement is always true, my compiler is fine with it. For example,
if (true) {
...
}
compiles.
Firstly, thank you ever so much for your reply- it has helped a lot! I'm still not quite sure about the following though:
> A runtime check? As in t.getClass()? Sure, but
> what benefit do you get from that?
Doesn't that allow you to check what real type argument the box class took initially when first instantiated? If you had a Box<String>, t would be of type 'String' and then using t.getClass() you could check what 'sort of a box' it was, find out that it was a 'Box of Strings' and therefore add other objects to the box knowing that they have to be Strings. I'm guessing you're gonna tell me that doesn't work though :P
> > and yet in the 'swap' method, you create an object
> of
> > type E called temp.
>
> No, you're creating a variable called "temp".
> That variable is assigned a reference to an
> existing object in your List.
Oh yeah- no new Object creation.
Following on from that then, using:
E tmp = a.get(i);
is synonymous to:
Object tmp = a.get(i);
because E erases to Object? If this is true, I hope I dont sount an absolute numpty in asking, why use E instead of Object in that example at all if all it is going to do at runtime is revert back to Object? Or does this have something to do with what you said about certain situations where E does not erase to Object?
Kazeha at 2007-7-29 16:12:04 >

I'd add some more duke stars but I'm not sure if I can.
After thinking a little more about my question, I think what I really don't understand is how you 'read' the following statement:
E tmp = a.get(i);
'E tmp;' declares a variable called 'temp' but of what type is it? simply Object? Then if that is the case, as I asked above, what is the point in declaring the variable as 'E tmp' and not 'Object tmp'?
Kazeha at 2007-7-29 16:12:04 >

> 'E tmp;' declares a variable called 'temp' but of
> what type is it? simply Object? Then if that is the
> case, as I asked above, what is the point in
> declaring the variable as 'E tmp' and not 'Object
> tmp'?
The real benefit to generics is not (normally) internal to the class, but in the interaction between the class and other classes in the application.
Consider the following (which might not compile):
public class <E extends Comparable> MyContainer
{
private List<E> _list = new ArrayList<E>();
public E getMax()
{
E temp = null;
for (E elem : _list)
{
temp = (temp == null) || (elem.compareTo(temp) > 0) ? elem : temp;
}
return temp;
}
}
Somewhere else in your application, you'd have code that looks like this:
MyContainer<String> foo = new MyContainer<String>();
...
String max = foo.getMax();
Pre-1.5, you would have to explicitly cast the result of getMax():
MyContainer foo = new MyContainer();
...
String max = (String)foo.getMax();
OK, so not having to cast is a nice thing. However, to keep the compiler happy, the class interface has to be able to represent the types held by the class -- so it's parameterized. And if you're returning an "E" (parameterized type) from a method, then the code in that method also has to be consistent, which means that temporary variables and whatnot need to be parameterized as well.
> > Because instanceof is a runtime check. E erases to
> > Object, which would of course make the conditional
> > always true. So the compiler prevents you from doing
> > it.
> Is that the reason why there is a compiler error
> here? If the condition of an if statement is always
> true, my compiler is fine with it. For example,
OK, I probably over-simplified there, and I suspect that the grammar (or more likely, tree analyzer) is defined such that only concrete types are allowed in that construct.
My point was that "x instanceof Object" is tautologically true. Therefore, any code that uses it is probably wrong, and in the case of a parameterized type would indicate that the programmer didn't realize that types are erased at runtime.
<quibble>
> My point was that "x instanceof Object" is
> tautologically true.
Unless x is null.
</quibble>
> OK, I probably over-simplified there, and I suspect
> that the grammar (or more likely, tree analyzer) is
> defined such that only concrete types are allowed in
> that construct.
>
> My point was that "x instanceof Object" is
> tautologically true. Therefore, any code that uses it
> is probably wrong, and in the case of a parameterized
> type would indicate that the programmer didn't
> realize that types are erased at runtime.
Thanks, makes sense now.