Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

rule changing in bounded wildcards in java-8?

I was following a tutorial about generics in Java defining this static method:

public static <T extends Comparable<T>> T min(T a) { ... }

and saying that

min(new GregorianCalendar());

couldn't compile because GregorianCalendar extends Calendar and Calendar implements Comparable<Calendar> so it implied that GregorianCalendar implements Comparable<Calendar> and NOT Comparable<GregorianCalendar>. So in order to compile the signature must be changed into:

public static <T extends Comparable<? super T>> T min(T a) { ... }

which is totally understandable. The 1st version of the method effectively doesn't compile in java-5 but it compiles in java-8! (i tried 5 through 8)

Why java-8 now allows that? (because it makes it more confusing now). What's the new "rule" behind that?

like image 628
sweetacaro Avatar asked Feb 10 '18 01:02

sweetacaro


People also ask

What happens when we use a bounded wildcard?

We use the Lower Bounded wildcards to widen the use of the type of variable. For example, if we want to add the list of integers in our method we can use the List<Integer>, but using this we will be bound to use only the list of integers.

What is bounded wildcard in Java?

A bounded wildcard is one with either an upper or a lower inheritance constraint. The bound of a wildcard can be either a class type, interface type, array type, or type variable. Upper bounds are expressed using the extends keyword and lower bounds using the super keyword.

What are the key differences between upper bounded wildcard and lower bounded wildcard?

The difference is on the compiler side. On the first one you can use the type (to cast something or use it as a bound to call another method for example) while on the second one, you cannot use it.

How we can define lower bound wildcard?

A lower bounded wildcard is expressed using the wildcard character ('? '), following by the super keyword, followed by its lower bound: <? super A>. Note: You can specify an upper bound for a wildcard, or you can specify a lower bound, but you cannot specify both.


2 Answers

Type inference!

There is a significant amount of information regarding this in JLS §18. Specifically, I'll direct you to JLS §18.2 (page 678) which states:

enter image description here

In your case, let S = GregorianCalendar and T = Calendar. This page states (during the reduction process) if S is a sub-type of T, then S is considered to be of type T (GregorianCalendar is treated as Calendar).

like image 186
Jacob G. Avatar answered Sep 22 '22 18:09

Jacob G.


The problem with your example is that you have written

min(new GregorianCalendar());

as a standalone expression. Prior to Java 8, this would be handled by the compiler by inferring GregorianCalendar for T which does not fulfill the constraint “… extends Comparable<T>”, so it gets rejected.

Starting with Java 8, the compiler infers Calendar for T, which fulfills the constraint, and it is valid to pass an instance of GregorianCalendar where Calendar is expected, so the example is accepted. It’s like if you hay written YourClass.<Calendar>min(new GregorianCalendar()); in previous Java versions.

However, this does not solve the fundamental problem of the min declaration that it doesn’t accept GregorianCalendar for T. While Java 8 allows you to write, e.g.

Calendar c = min(new GregorianCalendar());

using Calendar for T, it is still invalid to use GregorianCalendar for T, e.g.

GregorianCalendar c = min(new GregorianCalendar());

still will be rejected by the compiler.

Therefore, it is still necessary to use the declaration with wildcard

public static <T extends Comparable<? super T>> T min(T a) { ... }

to allow callers to use it like

GregorianCalendar c = min(new GregorianCalendar());
like image 35
Holger Avatar answered Sep 20 '22 18:09

Holger