Yes, it is known behaviour that if you use a raw type, then all type parameters on the class are lost, not just the type-level parameter that you failed to declare.
The issue is partly here:
If I specify the template of B like B<String>
, or if I remove the
template from B completely, then everything is ok.
That's not an option, you aren't to choose if you want to specify the type parameter or not. The only reason it compiles at all with no parameter specified is for backward compatibility. Writing new code with missing type parameters is a programming error.
List<A> list = b.getList()
does not successfully interpret the type, it is just effectively sticking in an arbitrary cast and trusting you that the assignment is correct. If you look at the compiler warnings it is in fact generating a warning for an unsafe conversion.
for(A a : b.getList()) {}
upgrades that warning to an error because the inserted cast would be inside compiler generated code, so it refuses to auto-generate unsafe code at all, rather than just give a warning.
From the java language specification:
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.
Bottom line really is that the only significant thing java generics share with C++ templates is the <> syntax :)
More details: What is a raw type and why shouldn't we use it?
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…