What is the general principle behind "parameter type compatibility" (whatever we can call it)?
Class<Base> cls1 = new Derived().getClass(); // ERR
Class<? extends Base> cls2 = new Derived().getClass(); // OK
Class<? super Base> cl3 = new Derived().getClass(); // ERR
Class<Base> cls4 = new Base().getClass(); // ERR
Class<? extends Base> cls5 = new Base().getClass(); // OK
Class<? super Base> cls6 = new Base().getClass(); // ERR
My answer:
Class<Base> cls1
in LHS expects exactly Class<Base>
in RHS => Class<? extends Derived>
is error.
Class<? extends Base> cls2
as per PECS means that anything we get from cls2 (by iterator or (imagine it exists) "get" methods) is Base (so that we can call base methods on what we got). Class<? extends Derived>
is Base in any case (be it Derived or its subclasses). So it compiles.
Class<? super Base> cls3
as per PECS means that we can always add Base to cls3 by (imagine it exists) "add/put" method - so Collection contains Base or its superclass. Class<? extends Derived>
can never be Base => Error.
I understand that new Derived().getClass()
returns Class<? extends Derived>
, likewise new Base().getClass()
returns Class<? extends Base>
.
I understand that List<? extends String> lst = new ArrayList<String>();
is OK and why.
I understand array covariance and covariant return types.
But the above set of test problems beats me - I cannot formulate rules that my reasoning shall be guided by.
P.S. PECS answers don't help me because mainly they view the problem in terms of "can I add or put or both into a collection/object". The focus of my question is on references compatibility.