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.
 
    