Interfaces and generics in Java

generics, interface, java

Solution

A `Set<Notifiable>` can hold instances of classes that implement `Notifiable`. It's not limited to holding only instances whose concrete type is `Notifiable` (and you're right, there's no such thing). But a `Set<Notifiable>` guarantees that it can hold any kind of `Notifiable`, since it has an `add(Notifiable)` method that can accept anything that implements the interface.

Suppose that you have some classes called `Foo` and `Bar` which both implement `Notifiable`. If you create a `Set<Foo>` — that is, a set that's only allowed to contain instances of `Foo` and its subtypes — you can't pass it to a method that takes a `Set<Notifiable>`, because that method may add things that aren't `Foo` instances, such as `Bar`.

public void addABar(final Set<Notifiable> notifiables) {
    notifiables.add(new Bar());  // OK, since Bar is a subtype of Notifiable
}

public void wontWork() {
  final Set<Foo> foos = new HashSet<>();
  addABar(foos);  // Compile error, can't convert Set<Foo> to Set<Notifiable>
}

But sometimes you want to write a method that can accept things like `Set<Foo>` and `Set<Bar>` in addition to `Set<Notifiable>`. That's where the wildcard comes in. A `Set<? extends Notifiable>` guarantees that everything in it is some kind of `Notifiable`, but it doesn't guarantee that every kind of `Notifiable` can be added to it; it's allowed to be limited to a subtype. You can't call `add()` on it, because that method is now `add(? extends Notifiable)` instead of `add(Notifiable)` and you can't call a method whose argument type is unknown.

You'd typically use this when you don't need to add elements, but you do need to look at the existing elements and call `Notifiable` interface methods on them, and you want to allow the the caller to pass sets of subtypes such as `Set<Foo>`.

For example:

public void notifyAll(final Set<? extends Notifiable> notifiables) {
    for (final Notifiable notifiable : notifiables) {
        notifiable.notify();
    }
}

public void example() {
    final Set<Foo> foos = whatever();
    notifyAll(foos);  // OK, since a Set<Foo> is a Set<? extends Notifiable>
}

If `notifyAll()` took a `Set<Notifiable>`, you wouldn't be able to pass `foos` to it.

Problem

I have the code: ``` Set<? extends Notifiable> notifiables; ``` Notifiable is an interface. I don't understand the difference between the above code and: ``` Set<Notifiable> notifiables; ``` If Notifiable was a class then I'd understand the difference, the first code would allow Notifiable and any subclass of Notifiable whereas the second code would only allow Notifiable (and not any subclasses) As you can't have an instance of an interface, what can I add/etc to the set? It seems to me there are only two options, either anything that implements Notifiable (in which case how is that different to the first code), or only "instances of Notifiable" which can't exist and so therefore nothing (which is pointless and should throw a compile time error).

Original source