Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ArrayList using addAll() compiler shows different behavior with generics [duplicate]

Can someone explain the following behavior to me?

I have a list of X and use the addAll() method to add elements. These elements are returned by a method using generic types. Method getA() returns < T extends A > with A being a class. Method getI() returns < T extends I > with I being an interface (see code below).

Difference: with listX.addAll(getA()) I get a compile error (as expected), but listX.addAll(getI()) compiles (throws a runtime error when element is cast to X).

Simpified code:

interface I {}
class A implements I {}

class X {}

public void test() {   
    List<X> listX = new ArrayList<>();
    listX.addAll(getA());

    listX.addAll(getI());
    for (X x : listX) {}
}
public <T extends A> List<T> getA() {
    return new ArrayList<>();
}
public <T extends I> List<T> getI() {
    return new ArrayList<>();
}

Am I missing something? Shouldn't I get a compile error both times?

That behavior seems to be new with Java 8, with versions below I have gotten compiler errors in both cases.

like image 306
firecat Avatar asked Jan 16 '17 09:01

firecat


People also ask

Do generics prevent type cast errors?

Implementing generics into your code can greatly improve its overall quality by preventing unprecedented runtime errors involving data types and typecasting.


2 Answers

I'd like to simplify the question and Shmosel's answer as follows:

interface I {}
class A implements I {}

class X {}

public void test() {   
    X temp = getI();  // compiles
    X temp2 = getA();  // does not compile
}

public <T extends I> T getI() {  
    return null;
}
public <T extends A> T getA() {  
    return null;
}

getI() can potentially return something that extends X and implements I, which is why it compiles. Normally, the type it actually returns would depend on something, for example an argument passed into the function.

getA() cannot return something that is an X, since it returns something that extends A, which does not extend X.

like image 139
Gonen I Avatar answered Nov 16 '22 01:11

Gonen I


listX.addAll(getA()); doesn't compile because there's no possible subclass of X that's also a subclass of A.

listX.addAll(getI()); does compile because there could be a subclass of X that also implements I.

like image 23
shmosel Avatar answered Nov 16 '22 01:11

shmosel