St.Antario
St.Antario

Reputation: 27385

Wildcard with extends

Code:

List<? extends Integer> ints= new ArrayList<Integer>();
ints.add(new SomeType());

I'm trying to reason why we cant add to ints formally. Please check the correctness.

Compiler always matched question mark to anonymous type CAP#n, where n is the ordinal number of wildcard declaration in the source code. From the fact that this wildrcard with extends implies that compiler internally assigned CAP#1 (in that case) just to anonymous type of null. But i'm not sure in this reason. Consider

List<? super Integer> ints= new ArrayList<Integer>(); 
ints.add(new Object());//error

In this case we have that compiler internally creates a new anonymous type, who marked CAP#2, such that only instance of all Integer's supertype is "instance of" CAP#2.

Question Do I understand the principle of wildcard's working correct now?

Upvotes: 0

Views: 116

Answers (2)

Judge Mental
Judge Mental

Reputation: 5239

Let's ignore the fact that Integer is final for purposes of this discussion.

When you give a variable the type of List< ? extends Integer >, the compiler does not allow you to call any method of List which has the generic type parameter as an argument to a method. These parameters are in what is known as contravariant position, and if the compiler would allow you to do what you are trying to do, Java's type system would be even more unsound than it already is. All the compiler knows is that the element type of the List is some unknown subtype of Integer, internally called CAP#1. Now attempting to call add( CAP#1, int ) with anything at all as first parameter will fail. The only exception is null, simply because unlike any other value in Java, null is a member of every reference type, so it must be a member of CAP#1. Note that the compiler will allow you to call any method of a List< ? extends Integer > that has no generic type inputs but possibly produces generic type outputs.

Contrary to the answer given by @Maxim Kirilov, when you give a variable the type of List< ? super Integer >, the compiler does not allow you to add any supertype of Integer. All it knows is that the unknown type is some supertype of Integer, internally called CAP#2, and that therefore anything which is an Integer or any subtype S of Integer can be added to the list (because no matter what CAP#2 turns out to be, S is a subtype of Integer which is a subtype of CAP#2, so add( CAP#2, int ) will accept an S in the first parameter).

By contrast, you are trying to call the method with an Object, which is not a subtype of Integer. The compiler rejects an attempt to pass an Object where a CAP#2 is required (as explained above).

Upvotes: 0

Maxim Kirilov
Maxim Kirilov

Reputation: 2739

Let's try to look at the presented problem in different view, from java.util.List

public interface List<E> extends Collection<E> {
    *
    *

    boolean add(E e);

    *
    *
}

When you specify List<? extends Integer>, the argument for add() becomes '? extends Integer'. From that description, the compiler cannot know which specific sub type of Integer is required there, so it won't accept any type of Integer.

The usage of List<? super Integer> tells to compiler that the it's possible to add to the list everything that is super type of Integer, addition of other types will violate static type safety.

You can thus begin to think of subtypes and supertypes bounds in terms of how you can "write" (pass into a method) to a generic type, and "read" (return from a method) from generic type.

Basically your technical description is right but I think that my explanation is more reasonable from static type safety point of view.

Hope it helps you.

Upvotes: 2

Related Questions