Java Generic : Can and Can’t

// 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?

*/
 

dicksonkho

 

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.