6

Consider the below code snippet:

// automatic casting works for int to byte conversion as integer literal 127
// is in the range for byte
byte b1 = 127; //OK

// automatic casting doesn't work for long to int conversion 
// even if long literal is in the range of int.
int i5 = 100L; // NOT OK - compilation error

Is there any explanation for such behavior?

Why is explicit conversion not needed in the case of int to byte, but needed for long to int?

The How does Java convert int into byte? question is different. It is about an issue in implicit conversion of int to byte when the int value is out of range.

Boann
  • 48,794
  • 16
  • 117
  • 146
Kanad
  • 1,008
  • 1
  • 11
  • 14
  • Java doesn't like the loss of conversion; it doesn't know that there is no real loss. – vandench Dec 29 '17 at 16:01
  • But why does it like in case of int to byte conversion? – Kanad Dec 29 '17 at 16:02
  • @AniketSahrawat same is case for int and byte.. – Kanad Dec 29 '17 at 16:03
  • Updated Question for more clarity: Why explicit conversion not needed in case of int to byte, but needed for long to int? – Kanad Dec 29 '17 at 16:08
  • Because `127` doesn't have a literal suffix Java is able to convert it to the appropriate type. – vandench Dec 29 '17 at 16:09
  • @Cyril That is up-scaling, that is still allowed. – vandench Dec 29 '17 at 16:25
  • This is exact duplicate of [How does Java convert int into byte?](https://stackoverflow.com/q/842817/573032). – Roman C Dec 29 '17 at 17:39
  • Nope. "How does Java convert int into byte?" question is different. It is about issue in implicit conversion of int to byte when int value is OUT OF RANGE. Please check description. – Kanad Dec 29 '17 at 18:09
  • @hnefatl my question was WHY this behavior (reason behind this behavior). And no post answers that question. Your answer mentions the fact that for Constant Expressions, JLS allow implicit narrowing conversion for some types and won't allow for some other. But it doesn't answer the question WHY? – Kanad Dec 31 '17 at 06:26
  • Could it be because of the way JVM's are implemented? - 1. JVM internally treats byte and short as int only. 2. Word size in JVM--: long need 2 words but int, short, byte all need only 1 word.. – Kanad Dec 31 '17 at 06:29
  • 1
    @simpleDev To know why the **JLS** is written as it is, you'll need to ask the Java developers, not ask on SO. It could've been an oversight/mistake, or make some rule in a parser nicer, or be to do with some minor thing associated with 32bit architectures when Java was designed. It's the same sort of question as asking why `++` was chosen as the increment operator. RE JVM implementation, there are lots of implementations out there and I doubt they all have the same word usage for data types. – hnefatl Dec 31 '17 at 09:29

1 Answers1

13

Widening conversions (eg. byte to int) are generally accepted implicitly by the Java compiler, as there's no loss of information (the range of int is greater than that of byte).

Narrowing conversions (eg. long to int, as in your case) can cause a loss of information, so are generally required to be explicitly casted.

See this similar question, and this. A relevant piece of the Java Language Specification:

Assignment conversion occurs when the value of an expression is assigned (§15.26) to a variable: the type of the expression must be converted to the type of the variable.

...

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.

(emphasis mine)


Some confusion stems from the fact that we're dealing in particular with constant expressions, as we're using numeric literals. The above spec also needs some careful reading.

To clear some things up and directly answer some of the OP's queries:

  1. Why implicit narrowing is supported for one type of narrowing and not the other?

    Ie. why does byte b1 = 127 work implicitly, while int i5 = 100L not?

    byte b1 = 127 performs an implicit conversion as (cf. the bold text in the above quote), "the value of the constant expression is representable in the type byte". That is, 127 is representable by a byte, so the conversion is implicit. If you try byte b1 = 128, you'll get an error about incompatible types, as 128 isn't representable by byte. The only reason we're allowed an implicit cast here at all is because we're using a constant expression.

    We don't get an implicit conversion in int i5 = 100L (even though 100 is in the range of int) as that's simply not listed in the allowed implicit conversions (the variable's type, int, is not one of byte, short, or char).

    We also don't get an implicit conversion in byte a = 0L, this time as the constant expression is of type long, not of type byte, short, char, or int.

  1. How will a normal programmer know which narrowing conversion is allowed implicitly?

    The implicit narrowing conversions only occur when you're assigning a constant expression to a variable. In these cases, implicit conversions are good as we don't want to be writing code like byte b = (byte)0 all the time. At the same time, we do want to be warned if we write something like byte b = 128, as that doesn't have intuitive behaviour.

    When we're not assigning constant expressions (so eg. int x = 0; byte b = x;), we always want to be warned when we're doing a potentially lossy conversion, as they're dangerous - so explicit conversions in this case also make sense.

hnefatl
  • 5,860
  • 2
  • 27
  • 49
  • 1
    I'm won't add anything here but saying that this is just a copy/paste from official docs. – Roman C Dec 29 '17 at 17:41
  • Thanks hnefatl. I still am not able to understand-: 1. Why implicit conversion is supported for one type of narrowing and not other. 2. How will a normal programmer know which narrowing conversion is allowed implicitly and which need explicit efforts. - Or programmer should wait till compilation error occur? If that's case then it's bizarre! – Kanad Dec 29 '17 at 17:59
  • @simpleDev I've attempted to answer those questions in my edit, let me know if anything else is unclear. – hnefatl Dec 29 '17 at 18:38
  • @RomanC I've edited my post to include an explanation of the relevant section of the language specification, as well as an analysis for this specific situation. – hnefatl Dec 29 '17 at 21:17
  • You don't understand the spec. which is wrongly interpreted by you. I don't mean that it's wrong but it's not the same meaning. – Roman C Jan 01 '18 at 01:56
  • @RomanC Which bit am I wrongly interpreting? I'm happy to correct mistakes. – hnefatl Jan 01 '18 at 02:37
  • 1
    @RomanC I've rolled-back your edit, as the text in question is a direct quote from a comment by the OP on this post. It's "normal" in the sense of "usual", not some masked insult. And throw me a bone or something, you've told me my interpretation's wrong but refuse to tell me why. Just give me a disproving code snippet or source countering this interpretation or anything. – hnefatl Jan 01 '18 at 03:12
  • If you have a question then there is the button to ask it. – Roman C Jan 01 '18 at 11:42