Lower bound generic in java does not compile even when passing super class
Asked Answered
S

3

5

List<? super IOException> means the list can contain IOException objects or any object that is super class of IOException. Then why the below Line 2 does not compile?

Also in Line 3 FileNotFoundException is not a super class of IOException. Then why it compiles?

List<? super IOException> myList =  new ArrayList<Exception>();
myList.add(new Exception());     //Line 2 This line do not compile
myList.add(new FileNotFoundException());  //Line 3 This compiles
Skulk answered 8/5, 2019 at 16:44 Comment(0)
D
7

The wildcard lower bound specifies a lower bound for the type argument, not for the acceptable types of the List. The type argument could be something as specific as IOException, but it could be as general as we can get: Object.

When adding an Exception, the type of the item is too general as an item, because the type parameter may be too specific for it -- it could be IOException. The compiler won't allow you to add an Exception to something that may take only IOExceptions, so it generates the error.

This doesn't occur with FileNotFoundException, because no matter how specific the type parameter is, it won't be any more specific than IOException (the lower bound), so a FileNotFoundException, which is a subclass of IOException, is legal in all cases, so the compiler allows it.

Downer answered 8/5, 2019 at 16:49 Comment(2)
Sorry I have a confusion. Here by writing ? super IOException I am specifying an Lower bound that the List can contain only the super classes of IOException and it cannot contain any sub class of it. So the compiler should allow to add Exception object and give error while adding FileNotFoundExceptionSkulk
As I've explained, you have a misunderstanding of what a lower bound is. It's a lower bound of the type parameter, not of the items the list may contain. You may assign a List<IOException> or a List<Object> to myList. But either way, you can add a FileNotFoundException to myList, because a FileNotFoundException is a subtype of any possible type parameter. But you may not add an Exception to myList, because the type parameter may be IOException.Downer
L
2

This:

myList.add(new FileNotFoundException());

compiles because FileNotFoundException is an IOException, just as it is an Exception, so it satisfies the bound of myList.

This:

myList.add(new Exception());

does not compile because the compiler does not know what exact type the list is (it doesn't check what was assigned to the varaible, it only looks at its declared type), so it doesn't know if the list assigned to it has a type that matches a super type of IOException, but not Exception.

This would happen is there was an intermediate class in the hierarchy between Exception and IOException. If the list actually had that type, Exception may not match the bound of the actual list assigned to myList.

The compiler doesn't check the complete class hierarchy nor what was assigned. It only does a basic check that always avoids runtime errors.

This is also true more generally where "logically" there is no code path that will cause an error, but the compile still fails.

Lablab answered 8/5, 2019 at 17:21 Comment(0)
O
0

myList references a List that could be List<IOException> or List<Exception> or List<Object>. Line 2 does not compile because we could have a List<IOException> and an Exception object wouldn’t fit in there

File-NotFoundException can also be added to any of those three types. This is tricky because FileNotFoundException is a subclass of IOException and the keyword says super.

The compiler looks at the reference type: List<? super IOException> all the possible types so:

List<Object>
List<Exception>
List<IOException>

then it goes across the line myList.add(new Exception()); and sees that it cant compile because it couldnt fit in the List<IOException>

Ology answered 8/5, 2019 at 16:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.