what actually happens here, when byte - byte is occur?
suppose,
byteResult = byte1 - byte2;
where,
byte1 = 0xff;
byte2 = 0x01;
then,
is byte1 turns into integer with value 255 and and byte2 1 and byteResult assigned to 254 then converted into byte with 0xFE? And then the if condition is checked? Please a detail help will be very helpful for me. Sorry if my question is ambiguous!
Here, I found something but not what exactly I want.
Java Byte comparison
No the byte will not be converted into an int.
From the JLS 5.2 Assignment Conversion:
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.
Also check subtracting 2 bytes makes int?
This is a basic premise of Java programming. All integers are of type int unless specifically cast to another type. Therefore, any arithmetic done with integers automatically 'promotes' all the operands to int type from the narrower type (byte, short), and the result of arithmetic with int operands is always int. (I think I've beaten that to death now).
If you want the short result of arithmetic with two bytes, do this:
short result = (short) (byte1 - byte2)
This explicit cast makes it the programmer's responsibility for throwing away the extra bits if they aren't needed. Otherwise, integer arithmetic is done in 32 bits.
Related
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.
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:
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.
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.
I know that the byte and the short data types are not given 2's complement treatment in Java. What I mean by this statement of mine is demonstrated in the example below:
byte b1 = 0xFF; //error, 255 is outside the range of byte
byte b2 = 0b1100; //12 is stored, and not -4
Now, take the following example:
byte b3 = 0;
b3 += 0xFF;
System.out.println(b3); //prints -1 on the console
Should the 2nd line in the above example have thrown an error, single 0xFF is 255 and is outside the byte range?
Also, what this unfair game with byte and short? I mean, why not interpret them using the 2's complement system, just like int and long?
They are 2's complement - no idea where you got that from (but it's wrong). This:
byte b1 = 0xFF;
does not work because it is indeed outside the range of a byte. This however:
byte b3 = 0;
b3 += 0xFF;
because += is done on a wider range of int, you assign it to byte, which takes the last 8 bits, which happen to be -1.
Rather than trying to work this out by attempting to draw logical inferences, you should read the Java Language Specification:
Point 1. byte and short are signed types.
"The values of the integral types are integers in the following ranges:
For byte, from -128 to 127, inclusive
For short, from -32768 to 32767, inclusive" Source JLS 4.2.1
Point 2. The signed integral types are 2's complement.
"The integral types are byte, short, int, and long, whose values are 8-bit, 16-bit, 32-bit and 64-bit signed two's-complement integers, respectively, and char, whose values are 16-bit unsigned integers representing UTF-16 code units (§3.1)." Source JLS 4.2
Point 3. You can't assign an int variable to a byte variable.
If the type of the right-hand operand is not assignment compatible with the type of the variable (§5.2), then a compile-time error occurs. Source JLS 15.26.1
Point 4. You can assign an int compile-time constant expression to a byte variable provided that the value of the expression is in the range of byte.
"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." Source JLS 5.2
Point 5. b3 += 0xFF is equivalent to b3 = (byte)(b3 + 0xFF)
Source JLS 15.26.2
Point 6. There are no byte or short literals.
Source JLS 3.10.1
if you want to convert -minus values java 8 comes with utility methods to support unsigned operations
byte b1 = (byte) 0xFF;
Byte.toUnsignedInt(b1); // this method will return 255
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.
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:
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.
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.
byte b = 0xFFFFFFFF; //OK, because integer -1 sits between -128 and 127, FINE!!
char ch = 0xFFFFFFFF; //Not OK, because integer -1 does not sit between 0 and 65535, FINE!!
byte b = 0L; //Compiler says Not OK? But long integer 0 sits between -128 and 127?
I am not convinced with narrowing rule applied by the java compiler in third line of above code.
Please help me understand, the logic behind this narrowing rule.
The L suffix on the literal 0L makes this literal of type long (a 64-bit signed integer).
There is no implicit narrowing from long to byte, according to the rules of the Java language.
See Java Language Specification section 5.2 Assignment Contexts:
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.
Note that the type of the constant expression does not include long.
There are two ways of casting a primitive data type into another. Explicit and Implicit.
Implicit casting as in your case byte b = 0L; gives compilation error as there is a possible loss of information.
If you change it like this:
byte b=(byte)0L;
Then there will be no compiler error, as you are telling compiler explicitely for the conversion.
i had a doubt in assigning or casting to a proper data type.
byte a=3; //compiled
byte b=5; //compiled
byte c=a+b; //not compiled and reporting as possible loss of precision.
here first two statements are compiling even though we are assigning int literal to byte.but what about third statement i am doing the same as above and that too value of a+b is in the range of byte .why there is such error?
The general rule is that you can not use assignment to narrow an integer to a byte, because that is an unsafe narrowing conversion (most ints don't fit in a byte). Specifically, none of the allowed assignment conversions may narrow.
However, there is an exception specifically for this case:
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.
This applies to a and b. The type of both variables is byte, and the values of both constant expressions clearly fit in a byte.
When you do the + operation on two bytes, they get implicitly converted to an int, so the result is an int as well. Therefore, you need another cast.
( The literal assignments in the first statement have nothing to do with it. )
I believe that addition performs binary numeric promotion, so a and b are being promoted to ints in the third statement.