Java widening conversions
Asked Answered
L

5

25

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?

Lipoprotein answered 13/8, 2014 at 19:11 Comment(5)
Why new Byte(int) won't compile? Because there is no constructor in the class Byte that except integer values as an argument. The compiler could also cast an integer argument, but no one implemented this feature yet. Why new Long(10) compiles? Because there is a suitable constructor available that excepts integer arguments. To assign long values you should write an l behind the number: Long l = 10L.Individualism
@Individualism Please post that as an answer. If you do, notify me and I'll upvote it.Overhappy
@Tom: Long doesn't have a constructor that accepts int argument. Long l = new Long(10) compiles because of implicit widening primitive conversion (int to long).Lipoprotein
@PhilipMathew That's why I said "suitable" at this point :D. (oh I did mentioned integer as the argument ... nevermind :D)Individualism
@Overhappy There are some good answers already. Upvote them. :)Individualism
E
20

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;
Electroform answered 13/8, 2014 at 19:18 Comment(0)
F
10

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.

Fcc answered 13/8, 2014 at 19:21 Comment(0)
S
1

10 is an integer literal, you have to downcast it to pass it to the Byte constructor. There unfortunately is no byte literal syntax to remove the cast either.

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

Because 10, an integer, can fit into a long with no issues. An integer cannot fit into a byte, so the cast is needed in that case (widening conversion).

This cast is compile time as well, as it's also a widening conversion. Check out section 5.1.5 in the JLS:

Widening reference conversions never require a special action at run time and therefore never throw an exception at run time. They consist simply in regarding a reference as having some other type in a manner that can be proved correct at compile time.

Slosberg answered 13/8, 2014 at 19:14 Comment(0)
P
1

Byte constructor takes either byte type or String type. See this

Constructor for Long takes long as an argument. Since long can take in integer, it allows it in the constructor.

Prostyle answered 13/8, 2014 at 19:17 Comment(0)
M
1

i think i have a solution for your problem...

//constructor for Byte class
Byte(byte value){

}

There are two rules for java type conversion

  1. Both types are compatible
  2. Destination type is greater than source type

Now in Your case you trying to convert int into byte which is against our second rule.... but below is the solution

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

Now let's talk about your Second issue...

 Long x = 10;//incompatible type

This is the issue of autoboxing... Now as we all know that autoboxing automatically converted primitive type into it's wrapper class.. But conversion not happens in case of autoboxing means....int is converted into Integer byte is converted into Byte.. Now when you assign int primitive type to Long, it gives you error of incompatible type....... Solution

Long x = (long) 10;//works fine....
Milano answered 13/8, 2014 at 19:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.