byte byteVar = 100 works but int intVar = 100L results in compilation error. Why?

Viewed 244

Integer literals can be assigned to byte or short variables as long as the value of the literal is within the range of byte/short.

But when long literal is assigned to int variable, compilation error is reported even when the value of long literal is within the range of int.

What is the logic explaining this?

Example,

The below line gets compiled successfully

byte byteVar =  100;   //works, here 100 is integer literal.

but

int intVar = 100L;   // fails, here 100L is long literal

results in compile time error.

Can someone please explain the underlying logic that drives this.

4 Answers

The actual reason is a bit more complicated than some of the other answers suggest.

JLS 5.2 states the following about the conversions allowed in an assignment context.

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 variable is of type 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 variable is of type Byte, Short, or Character, and the value of the constant expression is representable in the type byte, short, or char respectively.

The declaration / initialization

byte byteVar =  100;  // OK

works because all of the prerequisites are safisfied:

  • 100 is a constant expression
  • its type is int
  • its value is in the range of byte; i.e. it is representable as a byte
  • it is being assigned to a byte variable.

The declaration / initialization

byte byteVar =  100L;  // FAIL

fails because the type of 100L is long rather than int.

The logic for

int intVar = 100L;

not compiling is simply "why would you say L explicitly if you want it to be int? Probably a mistake somewhere, but we don't know if it's the type or the value which is wrong".

The more interesting part is why

byte byteVar = 100;

compiles instead of requiring you to write something like 100b. And I believe there are at least two reasons:

  1. the right part may be a constant expression, not just a literal: in

    byte byteVar = SOME_CONST + 3;
    

    you couldn't use a suffix, and the right-hand side is int even if SOME_CONST is byte.

  2. simply that C++ didn't have it and Java inherited a lot from C++.

L means 64-bit int integer primitive.

int intVar = 100L;

The following line will fail to compile because you are trying to place a 64-bit long primitive literal into a 32-bit int variable. It will give : // BAD — compiler fails — Cannot place a 64-bit long int primitive in a 32-bit int variable.

The byte format is an 8-bit integer format that can accept signed integer values in the range -128 to 127. Because the integer value 100 fits within this range,

byte byteVar = 100;

compiles; the integer literal is of a valid scale for what you are trying to store it in. https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html lists default values for the primitive data types and the table shows that byte, short and int all share the same value structure; an integer with nothing else associated to the literal.

The reason the int and 100L does not work is because the L suffix creates a long or Int64 literal. int is Int32, the 32-bit 2's complement signed integer format. By specifying that the value 100 should be of the 64-bit 2's complement signed integer format, this will not fit within 32 bits without an overflow, which is why the compiler does not allow that assignment.

Related