简体   繁体   中英

Weird behaviour of byte in java

I have this code:

public class First
{
    public static void main(String[] args)
    {
        byte b=50;
        byte c=b*2;  //Error    
        byte d=50*2;   //d=100
        byte e=(byte)258;   //e=258%256;
        byte f=(byte)128;  //f=128%256;
    }
}
  1. I know that any arithmetic expression involving byte is first promoted to int and then it is performed. Therefore I expected d=50*2 to also report an error, because the result of 50*2 is an int value and we are storing it in a byte without any explicit type cast. If Java does the casting implicitly, why does c=b*2 report an error?
  2. I know that if I want to store a value which is not within the range of a byte variable,then I have to explicitly type cast it into byte and the value that will be stored is the value modulo 256 (Size of byte). Therefore, why does byte f=(byte)128 return -128 ? Since 128 % 256 = 128 , so what I expect is f=128 , but it returns -128 . Why?

Thanks a lot.

This is because 50*2; will be resolved at compile time while b*2; will be resolved at runtime. So, at compile time Java compiler is sure that result of 50*2; will be 100. But in case of b*2; , as you have also mentioned that result of arithmetic operation is int , and compiler cannot be sure if result could exceed byte limits, so it complains and wants you to make sure the things by casting or changing type.

You can use javap -v Test.class to verify the same. See below:

 public static void main(java.lang.String[]);
   flags: ACC_PUBLIC, ACC_STATIC
   Code:
     stack=2, locals=2, args_size=1
        0: bipush        100
        2: istore_1
        3: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
        6: iload_1
        7: invokevirtual #3                  // Method java/io/PrintStream.println:(I)V
       10: return
     LineNumberTable:
       line 4: 0
       line 5: 3
       line 6: 10

For your second question, @Eran has already explained using bit representation of 128 and 258, and you can read further from JLS §5.1.3. Narrowing Primitive Conversion

A narrowing conversion of a signed integer to an integral type T simply discards all but the n lowest order bits, where n is the number of bits used to represent type T. In addition to a possible loss of information about the magnitude of the numeric value, this may cause the sign of the resulting value to differ from the sign of the input value.

As for your second question, when you downcast a numeric type, the low bits of the input are used to initialize the output.

Therefore, the int 128 , whose binary representation is 0......010000000 becomes the byte 10000000 (you take the low 8 bits), which is -128 .

On the other hand, 258 is 0........01000000010 , and when you take the low 8 bits you get 00000010 , which is 2.

Automatic Type Promotions in Java

In addition to assignments, there is another place where certain type conversions may occur: ie in expressions.

To see why, consider the following. In an expression, the precision required of an intermediate value will sometimes exceed the range of either operand.

For example, examine the following expression:

byte a = 40;
byte b = 50;
byte c = 100;
int d = a * b / c;

The result of the intermediate term a * b easily exceeds the range of either of its byte operands. To handle this kind of problem, Java automatically promotes each byte , short or char operand to int when evaluating an expression.

This means that the subexpression a*b is performed using integers—not bytes. Thus, 2,000, the result of the intermediate expression, 50 * 40, is legal even though a and b are both specified as type byte.

As useful as the automatic promotions are, they can cause confusing compile-time errors.

For example, this seemingly correct code causes a problem:

byte b = 50;
b = b * 2; // Error! Cannot assign an int to a byte!

The code is attempting to store 50 * 2, a perfectly valid byte value, back into a byte variable. However, because the operands were automatically promoted to int when the expression was evaluated, the result has also been promoted to int . Thus, the result of the expression is now of type int , which cannot be assigned to a byte without the use of a cast .

This is true even if, as in this particular case, the value being assigned would still fit in the target type. In cases where you understand the consequences of overflow, you should use an explicit cast, such as

byte b = 50;
b = (byte)(b * 2);

which yields the correct value of 100.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM