Please help me understand why add1() and add4() report errors and why add2() and add3() don’t. Specifically, please show examples of undesired consequences if the compiler allowed each of these to compile.
class InnerTypeConfusion {
interface Animal {}
class Dog implements Animal {}
class Room<T> {
void add(T t) {}
}
void add1(Room<? extends Animal> room) {
// Error: The method add(capture#1-of ? extends Animal) in the type
// Room<capture#1-of ? extends Animal> is not applicable for the
// arguments (Dog)
room.add(new Dog());
}
void add2(Room<Animal> room) {
room.add(new Dog());
}
class Cage<T> {}
void add3(Room<Cage<? extends Animal>> room) {
room.add(new Cage<Dog>());
}
void add4(Room<Cage<Animal>> room) {
// The method add(Cage<Animal>) in the type Room<Cage<Animal>> is not
// applicable for the arguments (Cage<Dog>)
room.add(new Cage<Dog>());
}
}
In the method
void add1(Room<? extends Animal> room), you define that the method accepts aRoomthat holds anAnimal. For example, it can beRoom<Cat>, orRoom<Dog>–evenRoom<Animal>for holding all types of animals. However, keep in mind that the room has been created outside this method call and you can’t make any assumptions about the room type other than that it holds either a specific animal.But once you’re inside the method, you can’t know specifically which type of room had been passed.
It would be valid to call the method with a room for only birds
add1(new Room<Bird>()), asBirddoes indeed extendAnimal. However in the method body, you are adding aDoginto it. That’s why it’s invalid, we can’t putDogobjects intoRoom<Bird>. It is aRoomof some kind of animals and not aRoomof any kind of animals.If you wanted to write a method that added a dog to a room appropriate for adding dogs (but not limited to just dog-only rooms), you’d write it with signature
addDogToRoom(Room<? super Dog> room)per this answer. This method could acceptRoom<Animal>as well asRoom<Dog>and still within the method add new dogs to the room.As about
add4, it’s the same but the opposite. WithRoom<Cage<Animal>>you specify that the method requires a specific room type–a room that allows only cages that hold any kind ofAnimal. But then you are trying to put aCage<Dog>into it, a cage that allows only dogs. Therefore, it’s invalid again.Addition regarding comment:
Let’s say there are cages designed for containing cats
Cage<Cat>and cages designed for containing dogsCage<Dog>. There are also universal cages, which can contain any kind of animalCage<Animal>. Those are three different kinds of cages, they can’t be substituted for one another, as they have totally different architecture and design.void method(Cage<Dog>)means that the method needs one dog cage.void method(Cage<Animal>)means that the method needs one universal cage.void method(Cage<? extends Animal>)means that the method needs any kind of animal cage. Either dog cage, cat cage or universal cage.Rooms are another level of abstraction–visualize them as a rooms with cages inside. There can be a room for storing cat cages
Room<Cage<Cat>>, a room for storing dog cagesRoom<Cage<Dog>>, a room for storing universal cagesRoom<Cage<Animal>>and a room for storing multiple kinds of animal cagesRoom<Cage<? extends Animal>>. Therefore, the same rules apply:void method(Room<Cage<Dog>>)– room of dog cagesvoid method(Room<Cage<Cat>>)– room of cat cagesvoid method(Room<Cage<Animal>>)– room of animal cagesvoid method(Room<Cage<? extends Animal>>)– room that can contain multiple kinds of animal cages. E.g., the room could simultaneously contain aCage<Dog>, and aCage<Animal>.Now, in
add3(Room<Cage<? extends Animal>> room), you request a last kind of room, the one that can contain “all kinds of animal cages”. Therefore the room passed to the method can contain or add new dog cagesroom.add(new Cage<Dog>())or any other type of cage.However, to call that method, you would need to first create a new “universal” room (which supports all cages):
Giving it a room of dog cages will not work:
If you wanted to write a more flexible method that accepts rooms capable at minimum of holding dog cages, it could look like this: