This code works, and I dont understand how the list is able to add a raw type box, I thought type erasure will set the type to their indicated bounds. note: Paper class doesn’t extends Bakery class.
EDIT: Is my understanding correct? the compiler typecasts the raw box type so that it can be added to the list? does this works only at compile time? so if I tried to get the value at runtime it will throw an exception?
class Violator { public static List<Box<? extends Bakery>> defraud() { List<Box<? extends Bakery>> list = new ArrayList<>(); Paper paper = new Paper(); Box box = new Box<>(); box.put(paper); list.add(box); return list; } } class Box<T> { void put(T item) { /* implementation omitted */ } T get() { /* implementation omitted */ } }
Advertisement
Answer
This code does generate an unchecked conversion warning, as to why its permitted, from Angelika Langer’s blog
Why are raw types permitted?
To facilitate interfacing with non-generic (legacy) code. Raw types are permitted in the language predominantly to facilitate interfacing with non-generic (legacy) code.
If, for instance, you have a non-generic legacy method that takes a
List
as an argument, you can pass a parameterized type such asList<String>
to that method. Conversely, if you have a method that returns aList
, you can assign the result to a reference variable of typeList<String>
, provided you know for some reason that the returned list really is a list of strings.
Your answer lies in Conversely, if you have a method that returns a List
, you can assign the result to a reference variable of type List<String>
. In your case you might have a legacy method that returns a Box
// Legacy code private Box getBox(){ // returns a Box which satisfy the Box<? extends Bakery> }
even though the returned result might satisfy the constraint Box<? extends Bakery>
, there is no way to be completely sure, so you are allowed to add that box to your list