Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java widening conversions

Tags:

I'm preparing for Java 7 certification and have the following question.

Byte b = 10 compiles ok. Looks like the compiler is narrowing int 10 to byte 10 and then boxing it. How come Byte b = new Byte(10) won't compile? Why can't the compiler narrow int 10 to byte 10 like it did in the first case?

Also how come Long l = new Long(10) compiles ok but Long l = 10 fails?

I'm not clear about how this works. Can somebody provide an clear explanation?

like image 881
Philip Mathew Avatar asked Aug 13 '14 19:08

Philip Mathew


People also ask

What is a widening conversion?

A widening conversion changes a value to a data type that can allow for any possible value of the original data. Widening conversions preserve the source value but can change its representation. This occurs if you convert from an integral type to Decimal , or from Char to String .

Does Java allow narrowing conversions?

Narrowing conversion is needed when you convert from a larger size type to a smaller size. This is for incompatible data types, wherein automatic conversions cannot be done. Let us see an example wherein we are converting long to integer using Narrowing Conversion.

What is widening and narrowing in Java?

In Java, there are two types of casting: Widening Casting (automatically) - converting a smaller type to a larger type size. byte -> short -> char -> int -> long -> float -> double. Narrowing Casting (manually) - converting a larger type to a smaller size type.

What is widening of data type with example?

A "widening" conversion or typecast is a cast from one data type to another data type, where the "destination" data type has a larger range compare to the "source" data type. For example: int to long. float to double.


2 Answers

Section 5.2 of the JLS covers the types of conversions that are allowed in assignment contexts.

Assignment contexts allow the use of one of the following:

  • an identity conversion (§5.1.1)

  • a widening primitive conversion (§5.1.2)

  • a widening reference conversion (§5.1.5)

  • a boxing conversion (§5.1.7) optionally followed by a widening reference conversion

Additionally,

In addition, if the expression is a constant expression (§15.28) of type byte, short, char, or int:

  • A narrowing primitive conversion may be used if the type of the variable is byte, short, or char, and the value of the constant expression is representable in the type of the variable.

  • A narrowing primitive conversion followed by a boxing conversion may be used if the type of the variable is:

    • Byte and the value of the constant expression is representable in the type byte.

    • Short and the value of the constant expression is representable in the type short.

    • Character and the value of the constant expression is representable in the type char.

Byte b = 10 compiles ok because 10 is a constant expression and is representable as a byte.

Byte b = new Byte(10) won't compile because 10 is an int literal, and method invocation conversion won't perform primitive narrowing conversions. To get this call to a Byte constructor to compile, you can explicitly cast 10 to byte:

Byte b = new Byte( (byte) 10); 

Long l = new Long(10) compiles because method invocation conversion will perform primitive widening conversions, including from int to long.

Long l = 10 won't compile, because Java will not specifically allow a widening conversion followed by a boxing conversion, as I discussed in a recent answer. To get this to compile, you can use a long literal, so only boxing is necessary.

Long l = 10L; 
like image 61
rgettman Avatar answered Oct 11 '22 10:10

rgettman


The basic rules are:

  • you can't convert-and-autobox in one step (JLS 5.1.7 defines the boxing conversions, and it doesn't include convert-and-autobox type conversions, so they're not allowed)
  • you can't implicitly narrow a type

These rules explain why Long l = 10 doesn't work, as well as new Byte(10). The first would require the int literal 10 to be widened to a long and then be boxed, which isn't allowed. (More precisely, it would require a conversion from int to Long, which JLS 5.1.7 doesn't define.) The second would require the int literal 10 to be implicitly narrowed to a byte, which isn't allowed.

But there are exceptions to the rule. Byte b = 10 is explicitly allowed by JLS 5.2:

In addition, if the expression is a constant expression (§15.28) of type byte, short, char, or int:

  • A narrowing primitive conversion followed by a boxing conversion may be used if the type of the variable is:
    • Byte and the value of the constant expression is representable in the type byte.

(some irrelevant parts omitted)

Lastly, new Long(10) works because the int literal 10 can be automatically widened to a long 10L.

like image 31
yshavit Avatar answered Oct 11 '22 11:10

yshavit