Let's say I have class Animal
and class Bear
which extends class Animal
.
Now in constructor I have parameter with Animal
:
public class Forest {
private List<Animal> animals;
public Forest(List<Animal> list) {
animals = list;
}
}
Why I cannot do something like that?
List<Bear> bears = new ArrayList<>();
new Forest(bears);
I thought that Bear
is in detail case Animal
.
Can I fix this only by adding template to Forest<P extends Animal>
?
Parameter Types We can use any data type such as primitive data types including int, float, double, char, short, byte, String, and object reference variables for a parameter of a method and constructor. There is no standard limit to specify the number of parameters in the definition of a method.
A parameter is a variable used to define a particular value during a function definition. Whenever we define a function we introduce our compiler with some variables that are being used in the running of that function. These variables are often termed as Parameters.
There may be times when you want to restrict the types that can be used as type arguments in a parameterized type. For example, a method that operates on numbers might only want to accept instances of Number or its subclasses. This is what bounded type parameters are for.
extends Number> represents a list of Number or its sub-types such as Integer and Double. Lower Bounded Wildcards: List<? super Integer> represents a list of Integer or its super-types Number and Object.
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);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With