I am learning Java. I found that expressions often have to be cast to a certain type in order to do it right. For example, during arithmetic evaluation, bytes are promoted to integers, so the following expression will throw an error:
byte b = 10;
int i;
i = b*b; //ok, assigning an integer evaluation to an integer variable
b = b*b; // throws error, coz assigning integer evaluation to byte variable
Now, I know that assigning an integer to a character variable is all right: char a; a = 88; is okay. However, if I do this:
char c2 = 'b', c3 = 'c';
c2 = c2 + c3; //throws error
c2 = (char)(c2 + c3); //works fine
Why does it throw an error when not casted? After all, the right hand side is still an integer, so assigning an integer to a character variable should work just fine.
In c2 + c3, both operands are implicitly widened to int, so the result of the addition is also an int.
JLS §15.18.2. Additive Operators (+ and -) for Numeric Types:
Binary numeric promotion is performed on the operands (§5.6.2).
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:
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.
You therefore end up with an int. Assigning it to a char variable requires an explicit cast.
You say:
Since integer value can be assigned to a character variable...
Only constant integer expressions can be assigned to a char variable without a cast.
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.
This automatic narrowing conversion doesn't apply here. You need an explicit cast.
It does not necessarily work fine to assign an int to a char. Chars are only 16 bit and ints are 32 bit, so the there might be an overflow.
In general Java only allows assignment of primitives values without cast if no overflow can occur as a result of the assignment.
char c2 = 'b', c3 = 'c';
c2 = c2 + c3; //throws error
c2 = (char)(c2 + c3); //works fine
when you doing c2+ c3
ASCII value of these chars are added which returns a int result.
when you are assigning int result to char it gives error.
Assigning an int 88 to a char works, because the compiler can determine the value.
The case c2 = c2 + c3 cannot be handled by the compiler. The value c2 + c3 must be evaluated at run time. Therefore, the compiler cannot determine the actual char value that has to be assigned.
char is 2 bytes and int is 4 bytes. When you write char c = 1; it does not mean that 1 is int, it's just a constant for javac and javac knows that 1 fits into char. But c2 = c2 + c3; is arithmetic operation, javac will interprets it as (int)c2 + (int)c3 and this produces int result. int does not fit into char so javac warns you that there may be lost of precision.
Have a look at thread:
Integer arithmetic in Java with char and integer literal
The reason seems to be that "c2 = c2 + c3;" cannot be checked by the compiler (it is executed in runtime) whereas "char a; a = 88;" is directly done by the compiler.
An example for further clarification:
char c1 = Character.MAX_VALUE;
char c2 = Character.MAX_VALUE;
char c3 = (char) (c1 + c2);
int i3 = c1 + c2;
System.out.printf("After casting to char: %s, the int value: %s%n", (int) c3, i3);
So with casting we actually got a wrong mathematical result.
There is a certain limit as to how much value each basic type can hold in java.Assigning the result of an arithmetic operation can produce an unpredictable result at run-time ,which JVM is unsure if char can hold,therefore the compilation error.
Related
When adding 'a' + 'b' it produces 195. Is the output datatype char or int?
The result of adding Java chars, shorts, or bytes is an int:
Java Language Specification on Binary Numeric Promotion:
If any of the operands is of a reference type, unboxing conversion
(§5.1.8) is performed. Then:
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.
But note what it says about compound assignment operators (like +=):
The result of the binary operation is converted to the type of the left-hand variable ... and the result of the conversion is stored into the variable.
For example:
char x = 1, y = 2;
x = x + y; // compile error: "possible loss of precision (found int, required char)"
x = (char)(x + y); // explicit cast back to char; OK
x += y; // compound operation-assignment; also OK
One way you can find out the type of the result, in general, is to cast it to an Object and ask it what class it is:
System.out.println(((Object)('a' + 'b')).getClass());
// outputs: class java.lang.Integer
If you're interested in performance, note that the Java bytecode doesn't even have dedicated instructions for arithmetic with the smaller data types. For example, for adding, there are instructions iadd (for ints), ladd (for longs), fadd (for floats), dadd (for doubles), and that's it. To simulate x += y with the smaller types, the compiler will use iadd and then zero the upper bytes of the int using an instruction like i2c ("int to char"). If the native CPU has dedicated instructions for 1-byte or 2-byte data, it's up to the Java virtual machine to optimize for that at run time.
If you want to concatenate characters as a String rather than interpreting them as a numeric type, there are lots of ways to do that. The easiest is adding an empty String to the expression, because adding a char and a String results in a String. All of these expressions result in the String "ab":
'a' + "" + 'b'
"" + 'a' + 'b' (this works because "" + 'a' is evaluated first; if the "" were at the end instead you would get "195")
new String(new char[] { 'a', 'b' })
new StringBuilder().append('a').append('b').toString()
String.format("%c%c", 'a', 'b')
Binary arithmetic operations on char and byte (and short) promote to int -- JLS 5.6.2.
You may wish to learn the following expressions about char.
char c='A';
int i=c+1;
System.out.println("i = "+i);
This is perfectly valid in Java and returns 66, the corresponding value of the character (Unicode) of c+1.
String temp="";
temp+=c;
System.out.println("temp = "+temp);
This is too valid in Java and the String type variable temp automatically accepts c of type char and produces temp=A on the console.
All the following statements are also valid in Java!
Integer intType=new Integer(c);
System.out.println("intType = "+intType);
Double doubleType=new Double(c);
System.out.println("doubleType = "+doubleType);
Float floatType=new Float(c);
System.out.println("floatType = "+floatType);
BigDecimal decimalType=new BigDecimal(c);
System.out.println("decimalType = "+decimalType);
Long longType=new Long(c);
System.out.println("longType = "+longType);
Although c is a type of char, it can be supplied with no error in the respective constructors and all of the above statements are treated as valid statements. They produce the following outputs respectively.
intType = 65
doubleType = 65.0
floatType = 65.0
decimalType = 65
longType =65
char is a primitive numeric integral type and as such is subject to all the rules of these beasts including conversions and promotions. You'll want to read up on this, and the JLS is one of the best sources for this: Conversions and Promotions. In particular, read the short bit on "5.1.2 Widening Primitive Conversion".
The Java compiler can interpret it as either one.
Check it by writing a program and looking for compiler errors:
public static void main(String[] args) {
int result1 = 'a' + 'b';
char result2 = 'a' + 'b';
}
If it's a char, then the first line will give me an error and the second one will not.
If it's an int, then the opposite will happen.
I compiled it and I got..... NO ERRORS. So Java accepts both.
However, when I printed them, I got:
int: 195
char: Ã
What happens is that when you do:
char result2 = 'a' + 'b'
an implicit conversion is performed (a "primitive narrowing conversion" from int to char).
According to the binary promotion rules, if neither of the operands is double, float or long, both are promoted to int. However, I strongly advice against treating char type as numeric, that kind of defeats its purpose.
While you have the correct answer already (referenced in the JLS), here's a bit of code to verify that you get an int when adding two chars.
public class CharAdditionTest
{
public static void main(String args[])
{
char a = 'a';
char b = 'b';
Object obj = a + b;
System.out.println(obj.getClass().getName());
}
}
The output is
java.lang.Integer
char is represented as Unicode values and where Unicode values are represented by \u followed by Hexadecimal values.
As any arithmetic operation on char values promoted to int , so the result of 'a' + 'b' is calculated as
1.) Apply the Unicode values on corresponding char using Unicode Table
2.) Apply the Hexadecimal to Decimal conversion and then perform the operation on Decimal values.
char Unicode Decimal
a 0061 97
b 0062 98 +
195
Unicode To Decimal Converter
Example
0061
(0*163) + (0*162) + (6*161) +
(1*160)
(0*4096) + (0*256) + (6*16) + (1*1)
0 + 0 + 96 + 1 = 97
0062
(0*163) + (0*162) + (6*161) +
(2*160)
(0*4096) + (0*256) + (6*16) + (2*1)
0 + 0 + 96 + 2 = 98
Hence 97 + 98 = 195
Example 2
char Unicode Decimal
Ջ 054b 1355
À 00c0 192
--------
1547 +
1163 -
7 /
260160 *
11 %
While Boann's answer is correct, there is a complication that applies to the case of constant expressions when they appear in assignment contexts.
Consider the following examples:
char x = 'a' + 'b'; // OK
char y = 'a';
char z = y + 'b'; // Compilation error
What is going on? They mean the same thing don't they? And why is it legal to assign an int to a char in the first example?
When a constant expression appears in an assignment context, the Java compiler computes the value of the expression and sees if it is in the range of the type that you are assigning to. If it is, then an implicit narrowing primitive conversion is applied.
In the first example, 'a' + 'b' is a constant expression, and its
value will fit in a char, so the compiler allows the implicit narrowing of the int expression result to a char.
In the second example, y is a variable so y + 'b' is NOT a
constant expression. So even though Blind Freddy can see that the
value will fit, the compiler does NOT allow any implicit narrowing, and you get a compilation error saying that an int cannot be assigned to a char.
There are some other caveats on when an implicit narrowing primitive conversion is allowed in this context; see JLS 5.2 and JLS 15.28 for the full details.
The latter explains in detail the requirements for a constant expression. It may not be what you may think. (For example, just declaring y as final doesn't help.)
package practicejava;
public class Query {
public static void main(String[] args) {
char ch = 66;
System.out.println("character= " + ch);
ch++;
System.out.println("character = " + ch);
}
}
Technically ch++; and ch=ch+1; are the same but why do I get an error when I write ch=ch+1; instead of ch++;?
You need to provide a cast in order to do that :
ch = (char) (ch + 1);
This is because the expression ch + 1 is is promoted (upcast) to an int. In order for you to reassign this expression to a char you need to explicitly downcast it.
By ch+1, the char ch will be promoted to int first, just like ((int)ch) + 1, so the result will be an int.
When you try assign an int(32 bit) back to a char(16 bit), it might loss accuracy, you need to do it explictly ch = (char)(ch + 1);
This is called Binary Numeric Promotion:
Binary numeric promotion is performed on the operands of certain
operators:
...
The addition and subtraction operators for numeric types + and - (§15.18.2)
and it will perform
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.
First of all, note that a char is 2 bytes large (16 bit), and an int is 32bit.
1. When typing ch++:
to apply the ++ operator, there is no type cast but the operator simply causes the bit represent of that char to increase by 1 to itself. Refer to JLS11 chapter 15.14.2,page 575:
The type of the postfix increment expression is the type of the variable.
2. When typing ch=ch+1:
ch is firstly casted to int, then it is added by 1(still an int), and the = is actually tring to cast the int which has 32bits into a char which has only 16 bits, note that this may lose accuracy. So without an explicitly cast, the compiler will complain about that, which is the cause of the error.
When adding 'a' + 'b' it produces 195. Is the output datatype char or int?
The result of adding Java chars, shorts, or bytes is an int:
Java Language Specification on Binary Numeric Promotion:
If any of the operands is of a reference type, unboxing conversion
(§5.1.8) is performed. Then:
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.
But note what it says about compound assignment operators (like +=):
The result of the binary operation is converted to the type of the left-hand variable ... and the result of the conversion is stored into the variable.
For example:
char x = 1, y = 2;
x = x + y; // compile error: "possible loss of precision (found int, required char)"
x = (char)(x + y); // explicit cast back to char; OK
x += y; // compound operation-assignment; also OK
One way you can find out the type of the result, in general, is to cast it to an Object and ask it what class it is:
System.out.println(((Object)('a' + 'b')).getClass());
// outputs: class java.lang.Integer
If you're interested in performance, note that the Java bytecode doesn't even have dedicated instructions for arithmetic with the smaller data types. For example, for adding, there are instructions iadd (for ints), ladd (for longs), fadd (for floats), dadd (for doubles), and that's it. To simulate x += y with the smaller types, the compiler will use iadd and then zero the upper bytes of the int using an instruction like i2c ("int to char"). If the native CPU has dedicated instructions for 1-byte or 2-byte data, it's up to the Java virtual machine to optimize for that at run time.
If you want to concatenate characters as a String rather than interpreting them as a numeric type, there are lots of ways to do that. The easiest is adding an empty String to the expression, because adding a char and a String results in a String. All of these expressions result in the String "ab":
'a' + "" + 'b'
"" + 'a' + 'b' (this works because "" + 'a' is evaluated first; if the "" were at the end instead you would get "195")
new String(new char[] { 'a', 'b' })
new StringBuilder().append('a').append('b').toString()
String.format("%c%c", 'a', 'b')
Binary arithmetic operations on char and byte (and short) promote to int -- JLS 5.6.2.
You may wish to learn the following expressions about char.
char c='A';
int i=c+1;
System.out.println("i = "+i);
This is perfectly valid in Java and returns 66, the corresponding value of the character (Unicode) of c+1.
String temp="";
temp+=c;
System.out.println("temp = "+temp);
This is too valid in Java and the String type variable temp automatically accepts c of type char and produces temp=A on the console.
All the following statements are also valid in Java!
Integer intType=new Integer(c);
System.out.println("intType = "+intType);
Double doubleType=new Double(c);
System.out.println("doubleType = "+doubleType);
Float floatType=new Float(c);
System.out.println("floatType = "+floatType);
BigDecimal decimalType=new BigDecimal(c);
System.out.println("decimalType = "+decimalType);
Long longType=new Long(c);
System.out.println("longType = "+longType);
Although c is a type of char, it can be supplied with no error in the respective constructors and all of the above statements are treated as valid statements. They produce the following outputs respectively.
intType = 65
doubleType = 65.0
floatType = 65.0
decimalType = 65
longType =65
char is a primitive numeric integral type and as such is subject to all the rules of these beasts including conversions and promotions. You'll want to read up on this, and the JLS is one of the best sources for this: Conversions and Promotions. In particular, read the short bit on "5.1.2 Widening Primitive Conversion".
The Java compiler can interpret it as either one.
Check it by writing a program and looking for compiler errors:
public static void main(String[] args) {
int result1 = 'a' + 'b';
char result2 = 'a' + 'b';
}
If it's a char, then the first line will give me an error and the second one will not.
If it's an int, then the opposite will happen.
I compiled it and I got..... NO ERRORS. So Java accepts both.
However, when I printed them, I got:
int: 195
char: Ã
What happens is that when you do:
char result2 = 'a' + 'b'
an implicit conversion is performed (a "primitive narrowing conversion" from int to char).
According to the binary promotion rules, if neither of the operands is double, float or long, both are promoted to int. However, I strongly advice against treating char type as numeric, that kind of defeats its purpose.
While you have the correct answer already (referenced in the JLS), here's a bit of code to verify that you get an int when adding two chars.
public class CharAdditionTest
{
public static void main(String args[])
{
char a = 'a';
char b = 'b';
Object obj = a + b;
System.out.println(obj.getClass().getName());
}
}
The output is
java.lang.Integer
char is represented as Unicode values and where Unicode values are represented by \u followed by Hexadecimal values.
As any arithmetic operation on char values promoted to int , so the result of 'a' + 'b' is calculated as
1.) Apply the Unicode values on corresponding char using Unicode Table
2.) Apply the Hexadecimal to Decimal conversion and then perform the operation on Decimal values.
char Unicode Decimal
a 0061 97
b 0062 98 +
195
Unicode To Decimal Converter
Example
0061
(0*163) + (0*162) + (6*161) +
(1*160)
(0*4096) + (0*256) + (6*16) + (1*1)
0 + 0 + 96 + 1 = 97
0062
(0*163) + (0*162) + (6*161) +
(2*160)
(0*4096) + (0*256) + (6*16) + (2*1)
0 + 0 + 96 + 2 = 98
Hence 97 + 98 = 195
Example 2
char Unicode Decimal
Ջ 054b 1355
À 00c0 192
--------
1547 +
1163 -
7 /
260160 *
11 %
While Boann's answer is correct, there is a complication that applies to the case of constant expressions when they appear in assignment contexts.
Consider the following examples:
char x = 'a' + 'b'; // OK
char y = 'a';
char z = y + 'b'; // Compilation error
What is going on? They mean the same thing don't they? And why is it legal to assign an int to a char in the first example?
When a constant expression appears in an assignment context, the Java compiler computes the value of the expression and sees if it is in the range of the type that you are assigning to. If it is, then an implicit narrowing primitive conversion is applied.
In the first example, 'a' + 'b' is a constant expression, and its
value will fit in a char, so the compiler allows the implicit narrowing of the int expression result to a char.
In the second example, y is a variable so y + 'b' is NOT a
constant expression. So even though Blind Freddy can see that the
value will fit, the compiler does NOT allow any implicit narrowing, and you get a compilation error saying that an int cannot be assigned to a char.
There are some other caveats on when an implicit narrowing primitive conversion is allowed in this context; see JLS 5.2 and JLS 15.28 for the full details.
The latter explains in detail the requirements for a constant expression. It may not be what you may think. (For example, just declaring y as final doesn't help.)
Can someone explain to me why the following code compiles OK in Java?
char c = 'a' + 10;
Why is this not equivalent to the following, which does not compile?
int i = 10;
char c = 'a' + i;
The Java Language Specification (section 3.10.1) states "An integer literal is of type long if it is suffixed with an ASCII letter L or l (ell); otherwise it is of type int (§4.2.1)." Section 4.2.2 refers to "The numerical operators, which result in a value of type int or long." So the result of the addition should, in my understanding, be an int, which cannot be assigned to the char variable c.
However, it compiles fine (at least in Sun JDK 1.6.0 release 17 and in Eclipse Helios).
Rather an artificial example perhaps, but it is used in an introductory Java course I have been teaching, and it now occurs to me that I don't really understand why it works.
It is because the compiler can check that it ('a' + 10) is within the bounds of a char whereas it cannot (in general) check that 'a' + <an integer> is within the bounds.
'a' + 10 is a compile-time constant expression with the value of 'k', which can initialise a variable of type char. This is the same as being able to assign a byte variable with a literal integer in [-128, 127]. A byte in the range of [128, 255] may be more annoying.
char is actually an unsigned 16-bit integer with a range 0-65535. So you can assign any integer literal in that range to a char, e.g., "char c = 96", which results in "c" holding the character "a". You can print out the result using System.out.println(c).
For the constant expression on the right-hand-side of "char c = 'a' + 10", 'a' is promoted to int first because of the Java numeric promotion rules and the integer value is 96. After adding 10 to it, we get a literal integer 106, which can be assigned to a char.
The right-hand-side of "char c = 'a' + i" is not a constant expression and the expression result assignment rule requires an explicit cast from int to char, i.e., "char c = (char) ('a' + i)".
This code should works:
int i = 10;
char x = (char)('a' + i);
The constant is of a different type (I know the spec says that 10 should be an int, but the compiler doesn't see it that way).
In char c = 'a' + 10, 10 is actually considered a constant variable of type char (so it can be added to a). Therefore char c = char + char works.
In int i = 10;
char c = 'a' + i; You are adding a char to an integer (an integer can be much bigger than a char, so it chooses the bigger data type [int] to be the result a.k.a: 'a' + i = int + int). So the result of the addition is an integer, which cannot fit into the char c.
If you explicitly casted i to be a char (e.g.: char c = 'a' + (char)i;) it could work or if you did the opposite (e.g.: int c = (int)'a' + i;) it would work.
According to Java specification as of 2020 for widening and narrowing conversions of integral values in expressions:
"In a numeric arithmetic context ... the promoted type is int,
and any expressions that are not of type int undergo widening
primitive conversion to int"
In assignment context:
"...if the expression is a constant expression 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."
So, in char c = 'a' + 10; the left constant value is a charand the right constant value is int fitting into a char. While there is an assignment and int 10 fits into char, int gets converted to char. And the overall result of addition is char.
And in char c = 'a' + i; (where int i = 10;) the i is not constant, so, notwithstanding the assignment, the char 'a' is promoted to int and the overall result is int. Thus, the assignment is erroneous without an explicit typecast.
Note, that the following original answer is wrong (it cites treatment in numeric choice contexts, like in switch statement):
According to Java specification for widening and narrowing conversions in expressions:
If any expression is of type int and is not a constant expression,
then the promoted type is int, and other expressions that are not of
type int undergo widening primitive conversion to int.
...
if any expression is of type char, and every other expression is
either of type 'char' or a constant expression of type 'int' with a
value that is representable in the type 'char', then the promoted type
is char, and the int expressions undergo narrowing primitive
conversion to char.
So, in char c = 'a' + 10; the left expression is a char and the right constant expression is int fitting into a char. So, the constant gets converted to char. And the overall result is char.
And in char c = 'a' + i; (where int i = 10;) the right expression is not constant, so the the char 'a' is promoted to int and the overall result is int.
The rules for promotion is "when operands are of different types, automatic binary numeric promotion occurs with the smaller operand type being converted to the larger". But the operands are of same type for example,
byte=byte+byte // Compile time error... found int..
So why is it so?
There's no + operator for byte. Instead, both operands are promoted to int, so you've got
byte = byte + byte
... becomes (widening to find + operator) ...
byte = int + int
... becomes (result of + operator) ...
byte = int
... which then fails because there's no implicit conversion from int to byte. You need to cast:
byte a = 1;
byte b = 2;
byte c = (byte) (a + b);
Here are the actual rules for numeric promotion, from section 5.6.2 of the JLS:
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, using widening conversion (§5.1.2) to convert operands as necessary:
If any of the operands is of a reference type, unboxing conversion (§5.1.8) is performed. Then:
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.
You were provided with correct answer about automatic promotion to 'int'.
There is one more note about that - compound assignment operators behave as they have an implicit type case. Example:
byte b1 = 1;
byte b2 = 2;
b1 = b1 + b2; // compilation fails
b1 += b2; // compilation successful
I would like to talk about Promotion in general
Java can evaluate only arithmetic expressions in which the operands’ types are identical
For example, in an expression containing int and double values, the int values are promoted to double values for use in the expression.
in another word
double someVar = 1 / 2;// someVar = 0
but
double someVar = (double)1 / 2;// someVar = 0.5
why?
we use the (double) cast operator to create a temporary
floating-point copy of its operand "1" (it's called explicit conversion)
The calculation now consists of a floating-point value (the temporary double copy of 1) divided by the integer 2
according to the above statement, Java performs an operation called promotion (or implicit conversion), so the int values are promoted to double values for use in the expression => the integer 2 is promoted to double
the expression became double someVar = 1.0 / 2.0; // someVar= 0.5
hope this is helpful, even if it is out of the core of the question
To understand this you should refer the 2 things:
Implicit Casting:
byte (8 bit) -> short (16 bit) -> int (32 bit) -> float (32 bit) -> double (64 bit)
char (16 bit) -> int (32 bit)
Arithmetic Operator Rules
Operator Precedence Rule : This rule states that Group of (*,/, %) will be evaluated first. Then Group of (+,-) operator will be evaluated. From a same Group of Operators, calculate from the left.
Operand Promotion Rule : This rule states that Operands having data type smaller than int will be promoted to int. order of promotion (byte->short->int, char->int)
Same Type Operand Rule: This rule states that if both operands are int,long,float,double then the same type is carried to the result type.
i.e. long+long => long , float + float => float, int+int => int
Mix Type Operand Rule : Follow the order of Promotion (int->long->float->double) if any of the operand is from the above order then the smaller will be promoted to the bigger one and result will be calculated in bigger type.
i.e. long + double => double , int + long => long
From this SO question, and above answers due to + arithmetic operator, both operands are converted to type int.
byte b1 = 1;
byte b2 = 2;
byte b3 = b1 + b2; // compile time error
In above code, value of b1 and b2 will be resolved at runtime, so compiler will convert both to int before resolving the value.
But if we consider the following code,
final byte b1 = 1;
final byte b2 = 2;
int b3 = b1 + b2; // constant expression, value resolved at compile time
b1 and b2 are final variables and values will be resolved at compile time so compilation won't fail.