In Java, polymorphism does NOT apply to generic types. So suppose class Child extends from class Parent, then the following 2 lines, only the first can pass compilation.
Parent var = new Child(); // compiler is happy with this
ArrayList<Parent> myList = new ArrayList<Child>(); // compilation error
The way to bring the idea of inheritance into Java generic types is using <? extends Parent> or <? super Child>. In this article we'll see how to understand the meaning of syntax <? super Child> in Java generics.
Check another article on how to understand syntax <? extends Parent> in Java generics.
0. Clarify concept
interface Animal{ }
class Dog implements Animal { }
class Cat implements Animal { }
public void test() {
// make sure you understand these 2 lines
List<Animal> pList = new ArrayList<Animal>();
pList.add(new Dog()); // It's fine
}
There is a List of type Animal variable pList. Can a Dog instance be added to this list? The answere is yes, because the Dog IS-A Animal;
1. Basic meaning
<? super Child> refer to any class that see class Child as its descendent.
<? super Child> can be used for variables definition and method's parameter, but most used in latter.
2. Make a collection (kind of) write-only
If generic types' syntax <? super Child> used as method's parameter definition, then the parameter is (kind of) write-only. Usually it's used with a collection parameter.
Why ? Let's image you have a method addDogToList defined like
void addDogToList (List<? super Dog> myList) {
myList.add(new Dog()); // design to add Dog to collection
Cat obj = (Cat) myList.get(0); // Compile OK, but risky!
// Never explicitly cast type
// when using generic types
}
The addDogToList has a paramenter myList as type List<? super Dog>. So the following usage are both correct since Dog instance can be add to a either Dog list or Animal List (see charter 0. clarify concept above)
addDogToList(new ArrayList<Dog>());
addDogToList (new ArrayList<Animal>());
we just explained why "write" to that list is OK, but why "write-only"? Technically speaking, you can read elements from collection marked by , but the return type is Object, which means you can cast it to any Class you want and the compiler will let you pass anyway, like what we did above, we cast element to type Cat, but during runtime that normally means a disaster. Furthermore, the whole meaning of Generics is to eliminate type casting for the sake of type-safe. That's why call it "kind of write-only" (you can read, but don't)
3. Recap
When use a collection variable with <? super Child> style, it means " Hey, I'm going to add Child instance into this collection, just make sure the argument passed in can hold new Child instance."
0 comments:
Post a Comment