Initializing a list of objects using polymorphism

I have a question about the application of polymorphism: let's say I have a Bird class, and I have many classes that extend it (for example, Pigeon , Falcon , etc.). Then I have a Cage class. In this class, I want to make a list of birds that live in this cage (only one bird can live in each cage).

Because of this, I don’t know the extended list type (A Pigeon ? Or maybe Eagle ?), The only thing I know is that it will be 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 can't I initialize something like this in the constructor: [...]

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

If you cannot do this, is it possible to achieve my goal differently?

+6
source share
5 answers

What you probably want is to use the common type for your cage to capture the exact type 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); } } 

Then you would use the cell as follows:

 Cage<Eagle> eagleCage = new Cage<Eagle>(); eagleCage.addBird(new Eagle()); 
+8
source

The reason you cannot execute List<Bird> birdList = new ArrayList<Pidgeon>() is because then someone can use the birdList link to write any Bird subclass to your ArrayList<Pidgin> . This should not be allowed by type checking; the Pidgin list should only contain Pidgin instances.

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

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 restricted lookup type like this says that the birdList compiler contains a list of an unknown subclass of Bird . This leads to the fact that you cannot add any elements to the list, since you cannot add the correct subtype, and when you read from the list, you will get links like Bird .

+4
source

Since only one species of bird lives in each cage, you can use Generic Types to enter your Cage class.

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

+2
source

You can not:

Bird List = new ArrayList ();

in java. The general type on the left should be absolutely equal (or perhaps it should not be equal if the wild card in the game extends T or? Super T) to the typical type on the right.

If it were possible, it would be impossible to add a new Eagle to the list declared as a Bird list - that would not make sense

What can you do:

 List<Bird> birds = new ArrayList<Bird>(); birds.add(new Pigeon()); 

(all Bird families, including Pigeon )

or

 List<? extends Bird> birds = new ArrayList<Pigeon>(); birds.add(new Pigeon()); // Adding is immpossible now - list can be read only now! 
+1
source

You can add arithmetic bird to your feeder, and then check the instance:

 private List<Bird> birdList; public Cage(){ this.birdList = new ArrayList<>(); birdList.add(new Pidgeon()); //... //Checking if it is a Pidgeon : if(birdList.get(i) instanceof Pidgeon) { //It is a pidgeon } } 
-1
source

Source: https://habr.com/ru/post/986039/


All Articles