The most confusing thing here is that whatever type restrictions we specify, assignment works only one way:
baseClassInstance = derivedClassInstance;
You may think that Integer extends Number
and that an Integer
would do as a extends Number>
, but the compiler will tell you that extends Number> cannot be converted to Integer
(that is, in human parlance, it is wrong that anything that extends number can be converted to Integer):
class Holder {
T v;
T get() { return v; }
void set(T n) { v=n; }
}
class A {
public static void main(String[]args) {
Holder extends Number> he = new Holder();
Holder super Number> hs = new Holder();
Integer i;
Number n;
Object o;
// Producer Super: always gives an error except
// when consumer expects just Object
i = hs.get(); // super Number> cannot be converted to Integer
n = hs.get(); // super Number> cannot be converted to Number
// super Number> cannot be converted to ... (but
// there is no class between Number and Object)
o = hs.get();
// Consumer Super
hs.set(i);
hs.set(n);
hs.set(o); // Object cannot be converted to super Number>
// Producer Extends
i = he.get(); // extends Number> cannot be converted to Integer
n = he.get();
o = he.get();
// Consumer Extends: always gives an error
he.set(i); // Integer cannot be converted to extends Number>
he.set(n); // Number cannot be converted to extends Number>
he.set(o); // Object cannot be converted to extends Number>
}
}
hs.set(i);
is ok because Integer
can be converted to any superclass of Number
(and not because Integer
is a superclass of Number
, which is not true).
EDIT added a comment about Consumer Extends and Producer Super -- they are not meaningful because they specify, correspondingly, nothing and just Object
. You are advised to remember PECS because CEPS is never useful.