Understanding Generics is quite simple, if you understand the following three basic principles:
1. The main purpose of having generics is to prevent corrupting (or polluting) a collection of objects. In other words, to avoid putting random things into any collection. After all, you want things neatly organized. You don't want to put apples in a sack of potatoes. Similarly, when you take things out of a sack of apples, you expect apples to come out and not potatoes or anything else. At the same time, if you have a "basket of fruit", you should be able to put any fruit such as an orange, an apple, or a Mcintosh apple into that basket. But, and here is the twist, when you pick a fruit from that basket, do you always expect to get an apple? No, right? You could get any fruit because it is a basket of fruits, and not a basket of apples!
That's the fundamental thing and the hardest to absorb (I bet you are rolling your eyes ).
Now, the simpler stuff:
2. ? extends Apple: This means "of a class that extends Apple". Therefore, List<? extends Apple> means a sack of some variety of Apple. Mcintosh? Probably. But you don't know. In other words, "? extends Apple" does not mean "any class that extends Apple". It means a specific but unknown class that extends Apple.
Q. When you are given a sack of "? extends Apple", can you put a Mcintosh in it? If you have any doubt, read point 1 again. (Hint: Do you want to mess up your sack of Fuji apples by putting a Mcintosh apple it it?)
Answer: No, you can't put a Mcintosh apple in a sack of "? extends Apple" because what if the sack is of Fuji apples? Putting a Mcintosh apple into a sack of Fuji apples would corrupt/pollute the sack of Fuji apples and we don't want that to happen.
Q. When you take out stuff from a sack of "? extends Apple", what do you get? An Apple for sure. Right? Could you get a Potato? A Mcintosh or a Fuji apple?
Answer: You will never get a Potato. You get some kind of Apple. You don't know the exact kind. It could be a Mcintosh or a Fuji apple but you have no idea which one. Therefore, you can assign it directly to a variable of type Apple but you cannot assign it directly to a variable of type FujiApple. You will need to cast it to assign it to a variable of type FujiApple.
The important thing is, why would anyone want to declare a variable of type List<? extends Apple> if they can't put any Apple into it? The answer is that they want to share their List of apples with others but they don't want others to pollute that list by adding random types of apples into that list. This property makes it very useful as return type of a method. For example,
Code: Select all
List<? extends Apple> getApples(){
return new ArrayList<FujiApple(); //the developer of the method is free to return an ArrayList of Mcintosh apples as well.
}
Code: Select all
List<? super Apple> listOfSuperApple = getListofSuperAppleSomehow();
listOfsuperApple.add(anApple);
listOfsuperApple.add(someFruit);
listOfsuperApple.add(aMac);
Answer:
Code: Select all
listOfsuperApple.add(anApple); //Correct, because any apple can be put in a sack that is meant to store apples, fruits, or fooditems, or Objects.
listOfsuperApple.add(someFruit); //Wrong, because what if the sack is of apples and someFruit is pointing to a Pineapple?
listOfsuperApple.add(aMac); //Correct, because any apple can be put in a sack that is meant to store apples, fruits, fooditems, or Objects.
Code: Select all
Apple a = listOfsuperApple.get(0);
Fruit a = listOfsuperApple.get(0);
FoodItem a = listOfsuperApple.get(0);
Object a = listOfsuperApple.get(0);
Answer:
Code: Select all
Apple a = listOfsuperApple.get(0); //Wrong, because you don't know the type of objects stored in the list. What if the list is of type FoodItems, and contains a Pineapple as well?
Fruit a = listOfsuperApple.get(0); //Wrong, what if the list is of type FoodItems, and contains a Pizza?
FoodItem a = listOfsuperApple.get(0); //Wrong, what if the list is of type Object and contains a String?
Object a = listOfsuperApple.get(0); //Correct, because no matter what is stored in the list, it is definitely an Object!
Quiz 1: What would List<?> mean? What can you put in it and what can you take out from it?
Answer <?> means something specific but not known. It doesn't mean "anything". It is like you get a sack from a fruit vendor and he tells you that it contains only a specific fruit, say Banana, but doesn't tell you exactly which fruit. It doesn't mean it contains various kinds of fruits. It contains only one kind of fruit but you don't know which one. If he sent you a sack of bananas, you can't put any fruit it in because you don't know the exact type of fruit it contains. Similarly, when you take something out from the sack of <?>, you can't assign it to any specific class other than Object because you don't know what exactly does the sack contain.
That's it! If you understand point 1 above, you will never miss any question on generics. Ever!
Quiz 2: Can you pass a List<String> to a method that accepts List<Object>?
Answer Think about what the code inside that method can do with a List<Object>. It can put any object in it, right? If you pass a List<String> to this method and if the method puts an Integer in it, what will happen? The list of Strings that you passed to it will now have an Integer in it. We don't want that to happen.