This question already has answers here:
Is addition of byte converts to int because of java language rules or because of jvm?
(6 answers)
Closed 6 years ago.
I have tyo byte variable
byte a = 3;
byte b = 4;
If I sum them, the value of sum is integer.
byte z = a+b //error, left side is byte, right side is integer
Why a+b is int?
Because the Java Language Specification says so
Binary numeric promotion is performed on the operands (§5.6.2).
Note that binary numeric promotion performs value set conversion
(§5.1.13) and may perform unboxing conversion (§5.1.8).
The type of an additive expression on numeric operands is the promoted
type of its operands.
and, regarding numeric promotion,
Widening primitive conversion (§5.1.2) is applied to convert either or
both operands as specified by the following rules:
[...]
Otherwise, both operands are converted to type int.
So the byte values are promoted to int values and added up. The result of the expression is the promoted type, therefore an int.
You can simply cast the result
byte z = (byte) (b + a);
but careful with overflow/underflow.
Related
when exactly does the widening primitive conversion happen in the program?
If I got an expression:
long l = 3L;
double d = 5.2L + l;
are 5.2L and l converted into double and then calculated, or is the calculation happening in long, with the result being converted to double afterwards?
The statement a = b + c consists of 2 operations:
Additive Operator +
JLS §15.18.2. Additive Operators (+ and -) for Numeric Types says:
Binary numeric promotion is performed on the operands (§5.6.2).
JLS §5.6.2. Binary Numeric Promotion says:
Widening primitive conversion (§5.1.2) is applied to convert either or both operands as specified by the following rules:
If either operand is of type double, the other is converted to double.
Otherwise, if either operand is of type float, the other is converted to float.
Otherwise, if either operand is of type long, the other is converted to long.
Otherwise, both operands are converted to type int.
Assignment Operator =
JLS §5.2. Assignment Contexts says:
Assignment contexts allow the value of an expression to be assigned (§15.26) to a variable; the type of the expression must be converted to the type of the variable.
Assignment contexts allow the use of one of the following:
an identity conversion (§5.1.1)
a widening primitive conversion (§5.1.2)
...
JLS §5.1.2. Widening Primitive Conversion says:
19 specific conversions on primitive types are called the widening primitive conversions:
byte to short, int, long, float, or double
short to int, long, float, or double
char to int, long, float, or double
int to long, float, or double
long to float or double
float to double
To re-cap, first the + operator causes the two operands to be widened to int, long, float, or double, whichever first covers both operands. The result of the + operator may then be further widened to fit the variable of the assignment.
Your original code
long l = 3L;
double d = 5.2L + l;
will not compile because 5.2L is not a valid literal.
In answer to your further questions:
which case would happen, if it was 5L instead?
In that case you would be adding two longs, and the result would be a long. That long would be converted to a double if you store it in a double variable.
And what would happen if there was an integer involved?
If you add an int and a long, you get a long. If you are assigning that to a double variable, it will subsequently be converted to a double.
byte a=10;
byte b=20;
b=a+b;
In this case, I need to explicitly convert a+b to byte like this :
b=(byte)(a+b);
It's the same with short :
short x=23;
short y=24;
Otherwise it gives an error.
But in case of integers, it's not required to convert explicitly :
int p=7788;
int q=7668;
p=p+q;
This will work just fine.
Why is that?
We don't need to explicitly cast even in the case of long as well.
If you look at the JLS 4.2.2 Integer Operations, it states that the result of a numerical operation between two integral operands is an int or a long. Since there's no implicit cast from an int to byte or a short, you need an explicit cast.
If you refer to JLS Sec 15.18.2, which deals with addition of numeric types, it says:
Binary numeric promotion is performed on the operands (§5.6.2).
...
The type of an additive expression on numeric operands is the promoted type of its operands.
JLS Sec 5.6.2 describes binary numeric promotion:
If any operand is of a reference type, it is subjected to unboxing conversion (§5.1.8).
Widening primitive conversion (§5.1.2) is applied to convert either or both operands as specified by the following rules:
If either operand is of type double, the other is converted to double.
Otherwise, if either operand is of type float, the other is converted to float.
Otherwise, if either operand is of type long, the other is converted to long.
Otherwise, both operands are converted to type int.
So, in the case of int and long (where both operands are of that type), binary numeric promotion is a no-op: the operands remain int and long respectively, and the result of the addition is int and long respectively, meaning the result can be assigned to variables of that type.
In the case of byte and short, binary numeric promotion causes both of those to be widened to int to perform the addition, and the result of the addition is int; you have to explicitly cast back again to the narrower type, because not all int values fit into a byte or short.
There are 2 exceptions to this requirement to do an explicit narrowing cast.
Firstly, compound assignments: this would have worked:
b += a;
because, as stated in JLS Sec 15.26.2:
A compound assignment expression of the form E1 op= E2 is equivalent to E1 = (T) ((E1) op (E2)), where T is the type of E1, except that E1 is evaluated only once.
In other words: the compiler inserts the cast for you:
b = (byte) ((b) + (a));
Secondly, if the operands have constant values, and the result of the addition is known to fit into the range of the narrower type, and you are doing the assignment at the variable declaration.
For example:
final byte a=10; // final is necessary for a and b to be constant expressions.
final byte b=20;
byte c = a + b;
This requires no cast.
With addition in java, java will promote the smaller data type to the larger one. And when the data type is smaller than int it will promote both the operant to int. Take a look at: Promotion in Java?
This question already has answers here:
XOR of two short integers
(3 answers)
Why does the Java API use int instead of short or byte?
(7 answers)
Closed 4 years ago.
If I compile this:
1 public class test {
2 public static void main (String args[]) {
3 byte bx = 1;
4 byte by = 2;
5
6 int iz = bx ^ by;
7 byte bz = bx ^ by;
8 byte cbz = (byte)(bx ^ by);
9 }
10 }
then I get this error:
test.java:7: error: incompatible types: possible lossy conversion from int to byte
bz = bx ^ by;
This led me on a brief journey resulting in me deciding ^ always results in an int in a bitwise context. I don't understand why that choice was made.
At first I thought it might have something to do with boxing (or unboxing) but I'm using a primitive type and so I don't think that is part of my confusion.
The only thing I can think of is that byte is promoted to int but I haven't found anything yet that says that's what happens.
Because, in Java, all numeric operators will promote operands to int, long, float, or double, as defined by JLS 5.6.2. Binary Numeric Promotion:
When an operator applies binary numeric promotion to a pair of operands, each of which must denote a value that is convertible to a numeric type, the following rules apply, in order:
If any operand is of a reference type, it is subjected to unboxing conversion (§5.1.8).
Widening primitive conversion (§5.1.2) is applied to convert either or both operands as specified by the following rules:
If either operand is of type double, the other is converted to double.
Otherwise, if either operand is of type float, the other is converted to float.
Otherwise, if either operand is of type long, the other is converted to long.
Otherwise, both operands are converted to type int.
After the type conversion, if any, value set conversion (§5.1.13) is applied to each operand.
Binary numeric promotion is performed on the operands of certain operators:
The multiplicative operators *, / and % (§15.17)
The addition and subtraction operators for numeric types + and - (§15.18.2)
The numerical comparison operators <, <=, >, and >= (§15.20.1)
The numerical equality operators == and != (§15.21.1)
The integer bitwise operators &, ^, and | (§15.22.1)
In certain cases, the conditional operator ? : (§15.25)
This question already has answers here:
=+ Operator in Java
(4 answers)
Closed 8 years ago.
Came across someone mistakenly using =+ instead of += in their code and it didn't show up as a compile error.
Is this because
int a =+ 2;
is the same as
int a = 0 + 2;
?
There's no compilation error because + is a valid (albeit fairly useless) unary operator in the same way that - is:
int x = +1;
int y = -1;
The relevant section in the Java Language Specification is Unary Plus Operator + (§15.15.3 ). It specifies that invoking the unary + operation results in Unary Numeric Promotion (§5.6.1) of the operand. This means that:
If the operand is of compile-time type Byte, Short, Character, or Integer, it is subjected to unboxing conversion
(§5.1.8).
The result is then promoted to a value of type int by a widening
primitive conversion
(§5.1.2)
or an identity conversion
(§5.1.1).
Otherwise, if the operand is of compile-time type Long, Float, or Double, it is subjected to unboxing conversion
(§5.1.8).
Otherwise, if the operand is of compile-time type byte, short, or char, it is promoted to a value of type int by a widening
primitive conversion
(§5.1.2).
Otherwise, a unary numeric operand remains as is and is not converted.
In any case, value set conversion
(§5.1.13)
is then applied.
In short, this means that
numeric primitive wrapper types are unboxed, and;
integer types smaller than int are widened to int.
There may be a bug lurking here. The writer may have intended to write a += 2;
In the original version of C, a += 2; and a =+ 2; were synonyms. If you meant a = +2;, you had to be careful to leave a space between the = and the +. Same with all the other operators. a=*p; multiplied a by p. a = *p; de-referenced the pointer p and assigned the result to a.
Then they came to their senses, and started giving warnings for =op where op= was probably intended, and now no longer accept =op at all.
But old habits die hard. An old-school C programmer might might still absent-mindedly use old-school syntax, even when writing in a language other than C.
On the other hand, the = in int x =+ 2; is an initialization, not an assignment, and it would be bizarre for a programmer to think in terms of incrementing a variable that is only just now being given its initial value.
This question already has answers here:
Adding char and int
(7 answers)
Closed 9 years ago.
I've got a strange issue with int to char conversion. Here's my code :
char a=100;
System.out.println(a);
System.out.println(a+1);
System.out.println();
System.out.println((char)a+1);
System.out.println((char)101);
System.out.println( (char)a+1==(char)101 );
It gave me this output :
d
101
101
e
true
which is definitly strange : two differents output seems to be the same when compared ! Why is it so ? And how to make a+1 beeing seen as a char ?
Thank you for your answer and sorry if there's some english mistakes, it's not my mothertongue.
In this case
System.out.println((char)a+1);
you are only converting the a to a char (which it is already). The addition makes the whole expression an int, so the overloaded PrintWriter#println(int) gets executed. For it to be seen as a char, do
System.out.println((char) (a+1));
In the JLS
The binary + operator performs addition when applied to two operands
of numeric type, producing the sum of the operands.
The type of an additive expression on numeric operands is the promoted
type of its operands.
and about promotion
Widening primitive conversion (§5.1.2) is applied to convert either or
both operands as specified by the following rules:
If either operand is of type double, the other is converted to double.
Otherwise, if either operand is of type float, the other is converted
to float.
Otherwise, if either operand is of type long, the other is converted
to long.
Otherwise, both operands are converted to type int.
When you use this way:
(char)a + 1
It firstly converts a => char, after this you add 1 of type integer.
And result of calculation is upcasted to integer type.
You can omit this tricky place if you will cast all expression together:
(char)(a + 1)