Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java compiler ignores type safety

public class POJO<T> {

    private List<Integer> integer = new ArrayList<Integer>();

    public POJO() {
        integer.add(1);
        integer.add(2);
    }

    public List<Integer> getInteger() {
        return integer;
    }

    public static void main(String[] args) {
        POJO pojo = new POJO();
        List<String> integer = pojo.getInteger(); // No compile error?
        System.out.println(integer); // prints [1, 2]
    }
}

How is it possible for the following line to compile:

List<String> integer = pojo.getInteger();

Provided getInteger() is typed as following

public List<Integer> getInteger()
like image 754
Farmor Avatar asked Aug 31 '12 10:08

Farmor


2 Answers

I found a reference in the JLS 4.8 that backs up what @PeterLawrey says:

The type of a constructor (§8.8), instance method (§8.4, §9.4), or non-static field (§8.3) M of a raw type C that is not inherited from its superclasses or superinterfaces is the raw type that corresponds to the erasure of its type in the generic declaration corresponding to C.

So all instance methods of your raw POJO object are erased, including those that don't reference the type T of POJO<T>, which means (JLS 4.6):

The type parameters of a [...] method (§8.4.4), and the return type (§8.4.5) of a method, also undergo erasure if the [...] method's signature is erased.

like image 107
assylias Avatar answered Nov 11 '22 08:11

assylias


As pojo is not declared as a generic

POJO pojo = new POJO();

the compiler assumes you are using it in pre-generic code. i.e. where generics were added after the code was written. So when you do

List<String> integer = pojo.getInteger(); 

You get a warning rather than an error.

i.e. If the type is non-generic, all generic checks are turn off, not just those which relate to the type you didn't give it. I believe this is for maximum backward compatibility.

For comparison.

Map mapOfInteger = new Map(); // no generics
Set<String> entries = map.entrySet(); // gives a warning, not an error.

In this example, You might expect Set<Entry<K, V>> to become Set<Entry> if not generic, but the compiler falls back to treating the class a non-generic Set.

like image 26
Peter Lawrey Avatar answered Nov 11 '22 07:11

Peter Lawrey