The SomethingThatExtendsA
class is a red herring here. You get the same problem with
List<String> list = new ArrayList<String>();
list.add("foo");
Iterator iterator = list.iterator(); // you should get a warning on this line...
String foo = iterator.next(); // ... and a compile error on this line
The issue is that raw types are a horrible ugly hack for backwards compatibility only which cause all the generics around them to stop working. Specifically, Iterator
is not the same type as Iterator<String>
, Iterator<Object>
, or even Iterator<?>
. Instead, Iterator
means "the Iterator
class I would have got if I had compiled with a pre-generics version of Java". Since the pre-generics version of Iterator
always returned Object
, then that's what you get. And you can't assign a value of type Object
to a more specific type (like String
, or your type B
) without a cast.
The Java Language Specification says this:
The use of raw types is allowed only as a concession to compatibility of legacy code. The use of raw types in code written after the introduction of genericity into the Java programming language is strongly discouraged. It is possible that future versions of the Java programming language will disallow the use of raw types.