Skip
Skip

Reputation: 6521

Java generics - method with "extends" typed collection parameter rejects valid argument?

I am trying to understand, why compiler rejects / accepts the following arguments.

I assumed, that both arguments would be accepted, because both Sets contain nothing, but children of Serializable.
And being a child of Serializable - is the only thing, which is enforced by method signature D extends Serializable - right?

Why is the Set serializables1 of type D extends Serializable accepted?
Why is the Set serializables2 of type ? extends Serializable rejected?
Why is D extends Serializable and ? extends Serializable is not the same here?

public class GenTest<D extends Serializable> {
    Set<D> serializables1;
    Set<? extends Serializable> serializables2;

    public static void main(String[] args) {
        GenTest<Serializable> g = null;

        g.accept(g.serializables1); // OK - WHY?
        g.accept(g.serializables2); // NOT OK - WHY?
    }

    void accept(Set<D> serializables) {}
}

Upvotes: 1

Views: 118

Answers (4)

Konstantin Yovkov
Konstantin Yovkov

Reputation: 62864

According to the signature, the .accept() method uses the class-scoped D type-parameter:

void accept(Set<D> serializables) {}

When instantiating GenTest as GenTest<Serializable> g = null; means that D will be replaced at Runtime with Serializable.

Now, what does Set<? extends Serializable> serializables2 mean?

It means that serializables2 can be assigned with a Set of unknown subclasses of Serializable. The compiler has no evidence that this unknown subclass will match the substitute of D at Runtime, and hence rejects to allow the code to compile.

Let's say you have these two types:

class A implements Serializable { }

class B implements Serializable { }

Set<? extends Serializable> serializables2 means that serializables2 can either be assigned with Set<A> or assigned with Set<B> at Runtime. Let's suppose it is assigned with Set<B>.

Now, if your g.serializables contain only objects of type A (which is possible, because the D is replaced by Serializable), this means that at Runtime you'll get a ClassCastException, when trying to pass a Set<B> to a method should be provided with a Set<A>.

More info:

Upvotes: 3

leftbit
leftbit

Reputation: 838

serializables1 contains a "Set of D", accept() accepts a "Set of D". The type hierarchy of D is not important. serializables2 can be any Serializable. Casting down to D is not possible.

Upvotes: 0

Smutje
Smutje

Reputation: 18123

Set<? extends Serializable> says exactly that the set contains a type which inherits Serializable but is not known so you have a kind of backwards compatibility to the pre-generics days without the possibility of changing the set - and your compiler has no knowledge whether ? complies to D in your example so he prohibits the given usage.

Upvotes: 0

user140547
user140547

Reputation: 8200

When using ? extends Serializable it can be an object of any class that implements Serializable and not just D, therefore it does not work.

Upvotes: 0

Related Questions