简体   繁体   中英

What is the Difference between a declaration using Generic Class and Generic Collections type

I will show you two style of declaration of generics. In part1, I'm using generic upper boundary declaration on List as follows:

List<? extends Animal> totList = new ArrayList<Animal>();

But this will throw error like below if you try to add a Animal object to the list:

Exception in thread "main" java.lang.Error: Unresolved compilation problem: 
    The method add(capture#1-of ? extends Animal) in the type List<capture#1-of ? extends Animal> is not applicable for the arguments (Animal)

    at GenericsType.main(GenericsType.java:39)

But as in Part2, if I declare the list inside a generic class in the format below, no errors are thrown while adding (Animal objects) or (subclass of Animal objects) to the list.

class GenericAnimal<T extends Animal> 
{    
   List<T> genList = new ArrayList<T>();
}

Why in part2, it didn't throw error and what is the difference between two style of declaration.

Example Code:

1.Animal.java

public class Animal {
    private String name;
    private int height;

    public void animalJump()
    {
        if(height>100)
        {
            System.out.println(name+" with height-"+height+" can JUMP");
        }
        else
            System.out.println(name+" with height-"+height+" cannot jump");         
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    public Animal(String name, int height) {
        setName(name);
        setHeight(height);
    }

}

2.GenericsType.java

import java.util.*;
import Animal;
import Animal.Cannine;
import Animal.Feline;
import Animal.Feline.Cat;
import Animal.Cannine.Dog;

public class GenericsType {

    public static List<? extends Animal> totList = new ArrayList<Animal>();

    public static void processAllfunc1()
    {
        for(Animal a : totList)
        {
            a.animalJump();
        }

    } 

    public static void main(String args[])
    {    
       // Part 1
        totList.add(new Animal("Animal1",21));  // Error: Unresolved compilation problem:           
        processAllfunc1();


       // Part 2
        GenericAnimal<Animal> genericanimal = new GenericAnimal<Animal>();
        genericanimal.genList.add(new Animal("Animal2",22));  // No Error, why?
        genericanimal.genList.add(new Cat("Cat4",204));      // No Error for Cat also, why?

        genericanimal.processAllfunc2();
    }
}

3.GenericAnimal.java

public class GenericAnimal<T extends Animal> {  

    public List<T> genList = new ArrayList<T>();

    public void processAllfunc2()  {
        for (T a : genList) {
            a.animalJump();
        }
    }
}

In part 2, the type of genericanimal.genList is List<T> = List<Animal> . In part 1, the type of the list is List<? extends Animal> List<? extends Animal> .

The issue is that List<? extends Animal> List<? extends Animal> means "a list of some specific subtype of Animal which is unknown." For example, you could write List<? extends Animal> list = new ArrayList<Cat>() List<? extends Animal> list = new ArrayList<Cat>() . And you shouldn't be able to add any animal to a list of cats. By writing List<? extends Animal> List<? extends Animal> , you're saying that you want to deliberately lose track of which type of animal is allowed into the list, though you know that whatever's in the list is some type of animal.

Why in part1, it threw error while trying to add an Animal object to the list?

List<? extends Animal> totList = new ArrayList<Animal>();
totList.add(new Animal("Animal1",21));  // Error: Unresolved compilation problem:

Because compiler restricts addition of objects on list declared using upper bounded wildcard( ? extends Animal). Compiler doesnt know for sure if the list is typed to the Animal, or Cat or Dog.

Simple, whenever a variable is declared using Upper bounded Wildcard, then inserting elements is not allowed to that variable.

Advantages of using Upper bounded Wildcard is that:

  1. You can create a method that can just read all elements (but no insertions) in the List.
  2. You can reuse that same method for the list of Animal or list of Dog or list of Cat.
  3. Also you can safely apply all methods of Animal on elements.

Why in part2, it didn't throw error while adding an Animal object and also Cat object to the list?

public List<T> genList = new ArrayList<T>();

genericanimal.genList.add(new Animal("Animal2",22));  // No Error, why?
genericanimal.genList.add(new Cat("Cat4",204));

Because Here genList is actually of type Animal like in below format

List<Animal> genList = new ArrayList<Animal>();

Now just like normal list of specific type, it can add elements of that type.

So an Animal object can be added to List Also Cat object is allowed to be added since it is also an Animal object only (Cat is just a subclass of Animal)

Advantages of using <T extends Animal> is that:

  1. You can read all elements of the List.
  2. You can insert elements to the List, but the element must be of type T.
  3. You can reuse the methods for Animal objects or Cat objects or Dog objects.
  4. You can safely apply all the Animal methods on elements.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM