Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Java Generics are invariant?

Tags:

java

generics

Compiling the below code is failing:

public static void swap(List<?> list, int i, int j) {
       list.set(i, list.set(j, list.get(i)));
}

like:

Swap.java:5: set(int,capture#282 of ?) in List<capture#282 of ?> cannot be applied to (int,Object)
           list.set(i, list.set(j, list.get(i)));

But if I do this:

public static void swap(List<?> list, int i, int j) {
       swapHelper(list, i, j);
}

private static <E> void swapHelper(List<E> list, int i, int j) { list.set(i, list.set(j, list.get(i)));
}

Its working perfectly.

But I have a basic doubt here. Generics are said to be invariant, so List<String> is not subtype of List<Object>, right?

If that is the case, then how come in the above method, we are able to pass List<?> to List<E>? How does this works?

like image 630
batman Avatar asked Oct 29 '25 12:10

batman


2 Answers

the answer is wildcards.

List<?> is not the same as List<Object> while java assumes both are collections of Object, the former will match the type of any other List<T>, while the latter will not match the type of any List<T> besides List<Object>.

example:

public void doSomething(List<Object> list);

This function will accept only List<Object> as it's parameter. However this:

public void doSomething(List<?> list);

will accept any List<T> as it's parameter.

This can be extremely useful when used with generic constraints. For instance if you'd like to write a function that manipulates numbers (Integers, Floats, etc.) you could:

public void doSomethingToNumbers(List<? extends Number> numbers) { ... }
like image 105
Assaf Avatar answered Nov 01 '25 02:11

Assaf


Because you are using wildcard capturing.

In some cases, the compiler infers the type of a wildcard. For example, a list may be defined as List but, when evaluating an expression, the compiler infers a particular type from the code. This scenario is known as wildcard capture.

Thanks to the helper method, the compiler uses inference to determine T, the capture variable, in the invocation.

like image 42
sol4me Avatar answered Nov 01 '25 02:11

sol4me



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!