Tricky interview question about generics, bounded wildcards and getClass()

Code Complete :

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.

Andy Turner :

Given an expression of type T, expression.getClass() returns Class<? extends T>, because expression is either a T or a subclass of T. (Strictly, it is a Class<? extends |T|>, where || denotes erasure; but that's unnecessary detail in the context of this question, where none of the values of T are generic).

Given this fact, expression.getClass() is neither Class<T> nor Class<? super T>, in the same way that a List<? extends Number> isn't a List<Number> or a List<? super Number>.

It doesn't matter if something is new SpecificSomething(): that's not a Class<SpecificSomething>, because the fact it's a new instance (and that it's guaranteed to be exactly a SpecificSomething) isn't taken into account: new SpecificSomething() is an expression of type SpecificSomething, so getClass() returns a Class<? extends SpecificSomething>.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=309603&siteId=1