简体   繁体   中英

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) {}
}

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 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 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:

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

Set<? extends Serializable> 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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM