tags:

views:

149

answers:

4

Please explain me why if I use the raw type A in the method test() , the get() method on my typed list returns an Object and not a B.:

public class test
{
    public class B{}
    public class C{}

    public class A<T extends C>
    {
        private List<B> aBList;

        public List<B> mGetBList()
        {
            return aBList;
        }
    }

    public test(A pA) // Use of raw type - this is bad, I know!
    {
        B lB = pA.mGetBList().get(0); // Compile error: Type mismatch: 
                                      // cannot convert from Object to test.B   

    }
}

If I declare

public test(A<?> pA)

the get() method returns a B as expected.

+1  A: 

+1 for interesting test case.

Looks like erasure erases everything, so in this case, you end up with.

public List mGetBList()

And erasure of List will result in public Object get( int ), which, of course, cannot be assigned to B.

If there is no strong need for raw type in method signature, use generic form that you have provided, otherwise cast the object to B

B lB = (B) pA.mGetBList().get(0);
Alexander Pogrebnyak
This is essentially what is happening. I asked a related question here: http://stackoverflow.com/questions/1073786/odd-generics-behaviour-of-list-toarrayt
waxwing
A: 

When you decalare your argument pa in the method test, no parameter is included, (including wildcard ). Therefore the list is held in a variable which contains a list of objects, so when you try to extract an element from the list you get a object, so you would have to cast it back to the required type, in this case B.

When using a wildcard the compliler is told not promote the list to a varibale containing an list holding Object. It is told that the contents are of the list are of 'unknown type' and is to be left alone. It is then upto the programmer to ensure that when extracting an element it is assigned to a suitable varibale, without using a cast.

chrisg
Why mark me down, tell me why when what i said is basicly the equivelant to the answer which has been marked up. It just has graeter abstraction.
chrisg
Because you don't name the "magical term": erasure. This is the concept that explains what happens here.
jumar
i didnt say it, i explained it in the first paragrapgh, the fact that the compliler does not know the type as it is held in an object reference so it must be cast back like the answer wich was marked up, and displays the code to cast the object back.
chrisg
@chrisg. I think jumar is too strict ( +1 )
Alexander Pogrebnyak
thanks appreciated, just trying to help.
chrisg
+2  A: 

"Doctor, it hurts when I do this."

Avoid raw types like the plague.

Kevin Bourrillion
I'm not trying to use a raw type, I just want to understand what happens. And your answer does not explain anything.
jumar
It's good to want to understand things. I'm just saying that the many weird things that can happen with raw types are not necessarily *worth* understanding, if you have the ability to avoid them. There's enough complicated stuff to understand about generics as it is; but we go through that complicated learning for a reason -- for all the benefits properly generified types give us.
Kevin Bourrillion
A: 

Ive been doing some digging around ang found this.

http://java.sun.com/docs/books/tutorial/extra/generics/legacy.html

Basically, erasure gets rid of (or erases) all generic type information. All the type information betweeen angle brackets is thrown out, so, for example, a parameterized type like List is converted into List. All remaining uses of type variables are replaced by the upper bound of the type variable (usually Object).

By upper bound im taking it if they mean < T extends C>, C would be the upper bound, then as only B is the type varibable for aBlist then its upper bound would be Object.

Anway hope this helps (Please dont mark me down again).

chrisg