// Assumption : Dog and Cat extends Animal
// SENARIO 1
List<Animal> animalList = new ArrayList<Animal>(); // YES
List<Animal> animalList = new ArrayList<Dog>(); // NO : Reason 1
// SENARIO 2
List<Animal> animalList = new ArrayList<Animal>();
animalList.add(new Dog()); //YES
animalList.add(new Cat()); //YES
// SENARIO 3
List<Dog> dogs = new ArrayList<Dog>();
dogs.add(new Dog());
sendBackHome(dogs); // YES
sendBackHomez(dogs); // YES
sendBackShop(dogs); // YES
sendBackShopz(dogs); // NO : Reason 2
static void sendBackHome(List<Dog> animals){
...
}
// Wildcard allow any type pass in as parameter but cannot add
static void sendBackShop(List<? extends Animal> animals) {
animals.add(new Dog()); //NO : Reason 2
}
// Wildcard allow any type pass in as parameter but cannot add
static void sendBackHomez(List<?> animals){
animals.add(new Dog()); //NO : Reason 2
}
static void sendBackShopz(List<Animal> animals){
...
}
static void sendBackShopz(List<Object> animals){
...
}
// SENARIO 4
void sendBackHome(List<? extends Serializable> animals) {} //YES
void sendBackHome(List<? implements Serializable> animals) {} //NO
// SENARIO 5
List<?> animals = new ArrayList<Dog>(); // YES
List<? extends Animal> animals = new ArrayList<Dog> // YES
List<? super Dog> animals = new ArrayList<Animal> // YES
List<? super Animal> animals = new ArrayList<Dog>; // NO
List<Animal> animals = new ArrayList<? super Dog>; // NO
//Wildcard notation cannot used in object creation
// SENARIO 6
public class Zoo<T extends Animal> {
public static void main(String[] args) {
Zoo<Dog> zoo = new Zoo<Dog>(); // YES
Zoo<Integer> zoo = new Zoo<Integer>(); // NO
}
}
// SENARIO 7
public class Zoo<T extends Serializable> {} // YES
public class Zoo<T implements Serializable> {} // NO
// SENARIO 8
public class Zoo<T extends Animal> {} // YES
public class Zoo<? extends Animal> {} // NO
// SENARIO 9
public class Zoo {
public <T extends Animal> Zoo(T t){} //Constructor
public static void main(String[] args) {
Zoo zoo = new Zoo(new Dog()); // YES
Zoo<Dog> zoo = new Zoo<Dog>(new Dog()); // NO
}
}
// SENARIO 10
public class Zoo {
public <T> void addAnimal(T t) {
List<T> animals = new ArrayList<T>(); // YES
animals.add(t);
}
}
public class Zoo {
List<T> animals = new ArrayList<T>(); // NO
public <T> void addAnimal(T t) {
animals.add(t);
}
}
/*
-------------------------- APPENDIX --------------------------
Reason 1
--------
Generic type of reference and object must identical.
Reason 2
--------
Due to type erasure, "animals" only recognize it's based type
which is ArrayList ONLY during runtime, and no other generic type.
Let's imagine senario below:
When we write this:
static void sendBackHome(List<Animal> animals){
animals.add(new Cat());
}
When runtime, what jvm see is only base type,
NOT generic type due to type erasure
static void sendBackHome(List animals){
animals.add(new Cat()); // now it content Cat and Dog object
}
See the problem ?
List<Animal> animals able to add Cat object.
when we try to process, animals list, which object should we cast?
*/