You can use wild card
private List<? extends Animal> animals; public Forest(List<? extends Animal> list) { animals = list; }
This allows the list to contain any animals, even a combination of different types.
All this compiles:
List<Bear> bears = new ArrayList<>(); new Forest(bears); ... List<Animal> mix = new ArrayList<>(); mix.add(new Animal()); mix.add(new Bear()); new Forest(mix);
The disadvantage is that you will not know the type, except that they are animals.
There are rules for when and when you can use wildcards and when to use extends vs super depending on whether you are placing new elements or not from the collection.
See an explanation of the get-put principle , sometimes called PECS, which stands for "Put Extends, Create Super"
EDIT
To add other animals to the list later, you must change the field of the list of animals so as not to use a wild card. However, the constructor can still use the wild card, but you should probably create a new List object, passing in the list from the constructor.
This will work:
private List<Animal> animals; public Forest(Collection<? extends Animal> list) { animals = new ArrayList<>(list); } public void add(Animal a){ animals.add(a); } public void addAll(Collection<? extends Animal> as){ animals.addAll(as); }
and then
List<Bear> bears = new ArrayList<>(); Forest forest = new Forest(bears); forest.add(new Animal());
I also added the addAll method, which also uses a wildcard
//same mix and bears lists from before Forest forest2 = new Forest(mix); forest2.addAll(bears);
source share