4

My question largely relates to this one Is List<Dog> a subclass of List<Animal>? Why aren't Java's generics implicitly polymorphic?

So, say we have Animal that is a super interface of Cat and Dog. We also have a abstract class Litter such that

public abstract class Litter{

    public Litter(Collection<Animal> animals){}
}

And then we naturally have a concrete class KittyLitter

public class KittyLitter extends Litter{

    public KittyLitter(Collection<Cat> animals) {
        super(animals);
    }
}

...and puppy litter.

Naturally, we want to limit all Animal in a KittyLitter to just Cat. Why doesnt Java allow us to do this? Then, also lets say we add another method --

public abstract void addCub(Animal animal);

and concrete implementation in KittyLitter of

@Override
public void addCub(Animal cat) {
    // TODO Auto-generated method stub
}

At this point this breaks logic and allows us to insert a Dog into a KittyLitter which makes no sense. Any ideas as to why Java does these things to us? Also, if KittyLitter constructor can be changed to accept a List, why does the type argument behave differently? Can anyone explain why this is so?

EDIT: this is really not about constructors, but also any method that overrides.

Community
  • 1
  • 1
aiguy
  • 671
  • 5
  • 20

2 Answers2

6

You need to make the superclass generic, using a bounded type parameter to say what kind of animals the litter can hold:

public abstract class Litter<T extends Animal> {  // <-- type bound
  public Litter(Collection<T> animals) { /* ... */ }
  public void addCub(T cub) { /* ... */ }
}

public class KittyLitter extends Litter<Cat> {
  public KittyLitter(Collection<Cat> cats) {
    super(cats);
  }
}

This allows the subclass to limit what kind of animals the inherited superclass methods will accept, by specifying a type for T. KittyLitter's addCub method takes a Cat argument, not an Animal. And PuppyLitter's addCub will take a Dog.

Wyzard
  • 33,849
  • 3
  • 67
  • 87
  • My question 'why does Java not allow Collection in KittyLitter constructor as opposed to Collection' as still unanswered, but as per Wyzards' answer there is an alternate mechanism to narrow down argument types. Accepting answer -- his solution is effectively, well, effective. – aiguy Aug 15 '15 at 16:05
  • That part was answered by the previous question you linked to. A `Collection` allows any kind of animal, including dogs. A `Collection`, obviously, doesn't. If a method wants a container that can hold any kind of animal, you can't give it one that's limited to a certain type. After all, there could be code in that method that adds dogs and cats and rhinoceroses to the collection you pass it. – Wyzard Aug 15 '15 at 17:04
0

Constructors are not overriding super constructors and you can declare them with any parameters you like. You can declare non-overriding methods with any parameters as well.

Overridden methods must be able to be called as if you call the parent directly so they cannot narrow parameter types. When Litter says it can be called with any Animal then it must be able to be called with any Animal.

StenSoft
  • 9,369
  • 25
  • 30
  • I dont think thats accurate. You can declare KittyLitter constructor with (ArrayList animals) arguments, and the super class Litter has arguments of (Collection animals). We're narrowing own from Collection all the way to ArrayList. – aiguy Aug 15 '15 at 01:59