JLS §5.2 of Java SE 11 contains some new type conversion cases which JLS of Java 8 doesn't have, see item 4 and item 5 in the list:
Assignment contexts allow the use of one of the following:
- an identity conversion
- a widening primitive conversion
- a widening reference conversion
- a widening reference conversion followed by an unboxing conversion
- a widening reference conversion followed by an unboxing conversion, then followed by a widening primitive conversion
- a boxing conversion
- a boxing conversion followed by a widening reference conversion
- an unboxing conversion
- an unboxing conversion followed by a widening primitive conversion
I don't understand the case 4 and case 5 in the list. Could anyone give me some explanation with examples? If possible, please also explain its practical usage.
Update:
As @Naman commented, here is the proposal to change the JLS - JDK-8166326 : 5.2: Allow widening before unboxing which was in effect since Java-9. In the report, it mentioned:
This behavior is especially important for interoperability with capture: various existing programs expect to be able to treat the elements of a
List<? extends Integer>
as if they were ints.List<? extends Integer> li = null; int i = li.get(0);
This may imply that this JLS change do have a practical necessary. But I still don't understand why <? extends Integer> is important. What does interoperability with capture mean and why is it important? What do these various existing programs look like? Are they java code (I know some other languages also work on JVM and may have interaction with Java code)?
It describes all aspects of the language, including the semantics of all types, statements, and expressions, as well as threads and binary compatibility.
Type Casting/type conversion Converting one primitive datatype into another is known as type casting (type conversion) in Java. You can cast the primitive datatypes in two ways namely, Widening and, Narrowing. Widening − Converting a lower datatype to a higher datatype is known as widening.
Implicit Type ConversionJava converts shorter data types to larger data types when they are assigned to the larger variable. For example, if you assign a short value to an int variable then Java does the work for you and converts the short value to an int and stores it in the int variable.
Java automatically promotes each byte, short, or char operand to int when evaluating an expression.
TL;DR
„…The problem with boxing is that it is [ad-hoc] and expensive; extensive work has gone on under the hood to address both of these concerns“ — Brian Goetz, State of Valhalla, March 2020
That makes me suspect that those changes to the spec you refer to are preparing the language for the planned „Codes like a class, works like an int“ capabilities of L-World discussed in the above link.
„…Could anyone give me some explanation with examples?…“
The example in the 2016 bug report linked to in the comments (plus the 2013 one that one links to) gives the best example of #4 in your list. Based on those, here's an example of #5 in your list…
< I extends Integer > void soAns0( I intRef ) {
int intPrim;
long longPrim = /* (3) a widening primitive conversion */
intPrim = /* (2) an unboxing conversion */
intRef; /* (1) a widening reference */
}
„…If possible, please also explain its practical usage…“
The natural numbers are often referred to as „integers“. The Java Language Tutorial shows one practical usage of restricting the natural numbers to only be of type Integer
…
public class NaturalNumber<T extends Integer> {
private T n;
public NaturalNumber(T n) { this.n = n; }
public boolean isEven() {
return n.intValue() % 2 == 0;
}
// …
}
There's also this example in the API documentation for RowFilter<M,I>…
…
public boolean include(Entry<? extends PersonModel, ? extends Integer> entry) {
…
Person person = personModel.getPerson(entry.getIdentifier());
…
}
…
Another use case where T extends Integer
might be appropriate is if you want to explicitly forbid your class from being parameterized with any other type of Number
AND explicitly forbid adding Integers
into that parameterized type — by leveraging the Get/Put Principle.
Say you have some code that, given some number, will create that number of objects.
If you want to forbid bad actors from overwhelming your system by bombarding it with Long.MAX_VALUE
number of DOS attempts, bounding <T extends Short>
could be one way to limit the number of objects that would get created in any one method call.
„…What do these various existing programs look like? Are they java code?…“
A search on github for T extends Integer
turns up eighty-thousand some hits.
„…What does interoperability with capture mean?…“
I defer the definitive explanation of capture conversion to the JLS itself.
„…and why is it important?…“
Capture conversion is important because of it's connection to type inference.
The notation ‹Integer <: α›
in the JLS' section on type inference is more or less a formal way of expressing Integer extends Integer
(what T extends Integer
effectively means)…
…
From
Arrays.asList(1, 2.0)
, we have the constraint formulas‹1 → α›
and‹2.0 → > α›
. Through reduction, these will become the constraint formulas‹int → α›
and‹double → α›
, and then‹Integer <: α›
and‹Double <: α›
.…
Given that, it's not surprising that the JDK uses <T extends Integer>
a lot for Generics/Type Inference related tests of the JDK itself.
Here's my absolute favorite use of <T extends Integer>
in the wild.
Mostly though, I would bet those unboxing-/widening-related changes to the spec have more than a little to do with Valhalla.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With