Shiran Shaharabani
Shiran Shaharabani

Reputation: 41

generic VS wildcards in Java

I have these two methods under a generic class:

public class Container<S> {
    public void f2(List<Object> l1, List<?> l2) {
        l1 = l2; //compilation error row #1
    }

    public void f3(List<?> c, List<S> l) {
        c = l; //ok row #2
        l = c; //compilation error row #3
    }
}

I really don't undersatand why row 2 is ok- if I transfer this method two lists, one is an object type list and one is a Strings one, I shoule get a compilation error?

would really appriciate to understadn why each row should/shouldn't be compiled.

Upvotes: 4

Views: 92

Answers (2)

J.Johnson
J.Johnson

Reputation: 89

Generics and wildcards are powerful because they ensure better typechecking during compile time, that's the main purpose of using them. To make sure your code won't break at runtime due to poor type checking.

Source

Although Integer is a subtype of Number, List<Integer> is not a subtype of List<Number> and, in fact, these two types are not related. The common parent of List<Number> and List<Integer> is List<?>.

In order to create a relationship between these classes so that the code can access Number's methods through List<Integer>'s elements, use an upper bounded wildcard:

List<? extends Integer> intList = new ArrayList<>();
List<? extends Number>  numList = intList;  // OK. List<? extends Integer> is a subtype of List<? extends Number>

Because Integer is a subtype of Number, and numList is a list of Number objects, a relationship now exists between intList (a list of Integer objects) and numList. The following diagram shows the relationships between several List classes declared with both upper and lower bounded wildcards.

To make use of subtyping and polymophism with wildcards you have to use bounded wildcards.

public void f2(List<Object> l1, List<?> l2) {
  l1 = l2; //compilation error row #1
}

//correct way of doing it
public void f2(List<? extends Object> l3, List<?> l4) {
  l3 = l4; 
}

Compiler doesn't see l2 as a subtype of l1

public void f3(List<?> c, List<S> l) {
  c = l; //ok row #2
  l = c; //compilation error row #3
}

Compiler doesn't see c as a subtype of l (rightly so, this could lead to runtime errors).

Upvotes: 1

Bohemian
Bohemian

Reputation: 424993

Why does this compile?

List<?> c, List<S> l;
c = l; // OK

List<?> means (more or less) “list of something” (or more formally “list of unknown”), and a List<S>is one of those.

——

Why does this not compile?

List<Object> l1, List<?> l2;
l1 = l2; //compilation error

If it were allowed, you could then add anything (eg String) to l1, but if l2 is anything other than List<Object> (eg Integer), you’d be putting the wrong type in l2. That’s why this assignment is not allowed.

The other compilation error is more subtle, and also doesn’t have a use case - that is, there’s no reason to assign a typed list to an untyped one - but the wildcard ? really means “unknown, but specific”. This is not the same as “anything”. It’s “something”, but we don’t know what. Type S is something, but the compiler can’t verify that it’s the same something as S.

Upvotes: 3

Related Questions