Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Initializing list of objects using polymorphism

I have a question on applying polymorphism: Let's assume I have a class Bird, and I have many classes that extend it (like Pigeon, Falcon and so on). Next, I have a Cage class. In this class, I want to make a list of birds which live in that cage (only one kind of bird can live in each cage).

Because of that, I do not know the extended type of the list (A Pigeon? Or maybe an Eagle?), the only thing i know is that it will be a Bird.

If Pigeon extends Bird

Using polymorphism I can declare a bird as: Bird tom = new Pigeon(); instead of Pigeon tom = new Pigeon();

So why I can't initialize something like that in the constructor: [...]

private List<Bird> birdList;

    public Cage() {
        this.birdList = new ArrayList<Pigeon>();
        /* Instead of birdList = new ArrayList<Bird>(); */
    }

If you cannot do that, is it possible to achieve my goal in another way?

like image 313
Thamiar Avatar asked Apr 27 '15 08:04

Thamiar


3 Answers

What you probably want is to use a generic type for your Cage to capture the exact kind of bird that lives in the cage. Like this:

import java.util.ArrayList;
import java.util.List;

public class Cage<T extends Bird> {

    private List<T> birdList;

    public Cage() {
        birdList = new ArrayList<T>();
    }

    public void addBird(T bird) {
        birdList.add(bird);
    }

}

You would then use the cage like this:

Cage<Eagle> eagleCage = new Cage<Eagle>();
eagleCage.addBird(new Eagle());
like image 69
Arne Deutsch Avatar answered Nov 14 '22 22:11

Arne Deutsch


The reason you can't do List<Bird> birdList = new ArrayList<Pidgeon>() is because then someone could use the birdList reference to write any Bird subclass to your ArrayList<Pidgin>. This must not be allowed by the type checker, a list of Pidgin must contain only Pidgin instances.

Arne gives one solution using a type parameter on Cage. If this is not what to want to do you can declare birdList with a wildcard type.

Your example would look like this:

class Bird {}
class Pidgeon extends Bird {}

class Cage {
    // This is a wildcard type and can contain lists of any
    // subtype to Bird, but you can't add elements to it.
    private List<? extends Bird> birdList;

    public Cage() {
        this.birdList = new ArrayList<Pidgeon>();
    }
}

An upper bounded wildcard type like this tells the compiler birdList contains a list of some unknown subclass to Bird. This has the effect that you can not add any elements to the list since you can not be sure to add the right subtype, and when you read from the list you will get references of type Bird.

like image 21
Lii Avatar answered Nov 15 '22 00:11

Lii


Since in each cage live only one kind of bird, you can use Generic Types to type your Cage class.

For example, Cage<T> will define a list of bird this way : List<T> birdList.

like image 42
yvilbe Avatar answered Nov 14 '22 22:11

yvilbe