You can use a wild card
private List<? extends Animal> animals;
public Forest(List<? extends Animal> list) {
animals = list;
}
This lets the list contain any kind of animals, even a mix of different types.
This will all compile:
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 downside is you won't know the type except that they are animals.
There are rules for if and when you can use wildcards and when to use extends
vs super
depending on if you are putting new elements or not from the Collection.
See the Explanation of the get-put principle which is sometimes called PECS which stands for "Put Extends, Create Super"
EDIT
To be able to add other animals to the list later, you have to change the animal list field to not 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);
}
then later
List<Bear> bears = new ArrayList<>();
Forest forest = new Forest(bears);
forest.add(new Animal());
I also added an addAll
method which also uses a wildcard
//same mix and bears lists from before
Forest forest2 = new Forest(mix);
forest2.addAll(bears);