Why final byte variable cannot be converted to Integer during auto-boxing? - java

There is no error when I try to autobox i2 to Byte,but when I do vise-versa(b1 to Integer),then an error occurs.
final byte b1 = 1;
Integer i1 = b1; //error
final int i2 = 1;
Byte b2 = i2;// no error
byte b3 = 1;
int i3 = b3; // no error

Can I suggest that you read JLS Sec 5.2, that I linked in my answer to your previous similar question.
Assignment contexts allow the use of one of the following:
an identity conversion (§5.1.1)
a widening primitive conversion (§5.1.2)
a widening reference conversion (§5.1.5)
a boxing conversion (§5.1.7) optionally followed by a widening
reference conversion
an unboxing conversion (§5.1.8) optionally followed by a widening
primitive 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.
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.
...
Taking your cases in reverse order:
byte b3 = 1;
int i3 = b3; // no error
Assigning a byte to an int is simply a widening conversion.
final int i2 = 1;
Byte b2 = i2;// no error
This is exactly the same as your previous question: you can assign a constant-valued int to a Byte, provided the value of that int fits into a byte.
final byte b1 = 1;
Integer i1 = b1; //error
You're trying to do a widening primitive conversion, followed by a boxing conversion. That's not one of the cases listed here, so it's an error.
You can fix this with an explicit widening cast:
Integer i1 = (int) b1; //ok

Related

Widening primitive conversions followed by boxing conversions [duplicate]

final byte b = 12;
Short s = b;
Integer i = b;
Program compiles fine for Short but for Integer compilation fails with "incompatible types" message.
I am having difficult time trying to understand this behavior. I could not find anything for this specific scenario..
I attempted to duplicate this with a wider group of assignment contexts:
final byte b = 12;
Byte b2 = b;
Character c = b; // Only an error if b isn't final
char c2 = b; // Only an error if b isn't final
Short s = b; // Only an error if b isn't final
short s2 = b;
Integer i = b; // Error, as indicated in the question
int i2 = b;
Long l = b; // Also an error
long l2 = b;
Float f = b; // Also an error
float f2 = b;
Double d = b; // Also an error
double d2 = b;
Assigning not just to a Integer, but also to a Float, a Long or a Double is also an error.
Interestingly, if the original declaration of b was NOT final, then assigning to a Character, a char, or a Short fails also.
Section 5.2 of the JLS sheds a little light on the subject of assignment contexts and their allowed conversions.
Assignment contexts allow the use of one of the following:
an identity conversion (§5.1.1)
a widening primitive conversion (§5.1.2)
a widening reference conversion (§5.1.5)
a boxing conversion (§5.1.7) optionally followed by a widening reference conversion
an unboxing conversion (§5.1.8) optionally followed by a widening primitive conversion.
This covers all of the conversions to wider primitive variables, which are always allowed, whether b is final or not. (That holds unless b is negative, in which case the assignment to an unsigned char (or Character) would fail.) Continuing:
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.
Because b is final, the expression b is a constant expression, allowing it to be narrowed from the int constant expression 12 to byte, char, or short and then boxed to Byte, Character, or Short, but strangely, not to Integer or anything "above". The only possible explanation I can think of is that constant expressions that are subject to a primitive narrowing conversion aren't specifically allowed to be converted to Integer, Long, Float, or Double.
If b isn't final, then the narrowing followed by boxing isn't allowed, and a non-constant expression can't be promoted from byte to char either.

Java char to byte casting

I have been testing the char casting and I went through this:
public class Test {
public static void main(String a[]) {
final byte b1 = 1;
byte b2 = 1;
char c = 2;
c = b1; // 1- Working fine
c = b2; // 2 -Compilation error
}
}
Can anyone explain why it's working fine in 1 when I added a final to the byte?
When the variable is final, the compiler automatically inlines its value which is 1. This value is representable as a char, i.e.:
c = b1;
is equivalent to
c = 1;
In fact, according to this section on final variables, b1 is treated as a constant:
A variable of primitive type or type String, that is final and initialized with a compile-time constant expression (§15.28), is called a constant variable.
The conversion from byte to char is a widening and narrowing primitive conversion, as described in paragraph 5.1.4 of the Java Language Specification.
As the JLS describes, this is done via an intermediate step; the byte is converted to int via a widening primitive conversion and then the int is converted to char via a narrowing primitive conversion (see 5.1.3).
Paragraph 5.2 explains when a cast is necessary when you do an assignment:
... 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.
Your variable b1 is indeed a constant, but your variable b2 is not, so this rule applies for b1 but not for b2.
So: you can assign b1 to c because b1 is a constant and the value of the constant, 1, fits in a char, but you cannot assign b2 to c without a cast because b2 is not a constant.
Well , its because byte is a signed type while char is not, so u need to apply explicit type conversion for (2)
c = (char)b2;
also the final statement worked for 1 because prior to compilation , the compiler is able to confirm that there is no loss due to conversion since '1' is in the range of char , try putting '-1' with the same final statement in (1) you will again get a compilation error.
All this boils down to the type compatibility between signed and unsigned types..which needs to be done explicitly in java.

Multiplying two bytes

Can somebody explain me why I can't to multiply two bytes in this way?
byte a = 1;
byte b = 1;
byte c = a*b;
or
byte a = 1;
byte b = 1;
short c = a*b;
Why I have to do that in this way?
byte a = 1;
byte b = 1;
byte c = (byte)(a*b);
or
byte a = 1;
byte b = 1;
int/double/float/long c = a*b;
When performing math with bytes, binary numeric promotion takes place, as specified by the JLS, Section 5.6.2.
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.
(emphasis mine)
That forces you to assign to a type that is at least as wide as int or to cast back to byte.
Product of two bytes will not necessarily fit into a byte. So Java needs you to tell it that you know what you are doing and confirm that in case of overflow you will get the low-order bits.

Rules for typecasting with byte

I was just playing around with type casting. Here's the code:
class Typecasting {
public static void main(String[] args) {
byte b = 3;
byte c = b++; // no error
byte d = b + 1; // error
byte e = b + b; // error
}
}
Why is there no error in the first line but in second?? Also when i do
f = b + 2;
I understand that b was automatically cast into int type and therefore f must be int type but when I do
e = b + b;
they both are byte type and their result is also in the range of a byte, so why can't e have byte data type? Is it due to the + binary operator?
Why is there no error in the first line but in second?
Because that's the way the language is defined. There's no byte + byte operator, which is why the third line fails - both operands are promoted to int automatically. From section 15.18.2 of the JLS:
The binary + operator performs addition when applied to two operands of numeric type, producing the sum of the operands.
...
Binary numeric promotion is performed on the operands (§5.6.2).
Now binary numeric promotion always ends up with a value of int, long, float or double... int in this case. So the operation is to add two int values together, and the result is an int.
For b++, however, the type is still byte. It's a postfix increment expression (section 15.14.2):
The type of the postfix increment expression is the type of the variable.
On a related note, this would be okay:
b += 3;
That's a compound assignment (section 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.
Note the casting part, which is why it works.
+(byte, byte) returns an int per the rules of the language.
The relevant section of the spec is §5.6.2:
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.
Whereas for ++, the type of the result is the type of the operand. From the JLS, §15.14.2:
The type of the postfix increment expression is the type of the variable.
Thus, for b++, the result is a byte and so is assignable to c.
byte d = b+1;
In here you are assign int value(b+1) to byte d. When you added a int vale to byte value it becomes int value.
byte c = b++; //No error;First Line
This conforms to JLS 15.14.2
The type of the postfix increment expression is the type of the variable. The result of the postfix increment expression is not a variable, but a value.
byte d = b+1; //error;Second Line
byte e = b+b; //error;Third line
This conforms to JLS 15.18.2
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.
If this promoted type is int or long, then integer arithmetic is performed.
Read about type promotion in JLS 5.6.2
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.
in line first ++operator returns always operand type result..so it gives no error
in second line here 1 is an integer type because all integer type literals is int by default
in third line +(byte,byte) returns the integer type that why it will forces you to type cast it into int.
--> in third line there is always a probability to overflow in byte type..
* if your byte type is defined as constant then it will not force you to typecast because it will alwayz be in range.
When Java performs a sum, it first "transforms" both operands to int or long (depending of the operands) and the result will be an integer, which will try to assign to your variable of type byte, as it "realizes" the result wont fit in a byte, then it will "complain" and you wont be even able to compile this.

Promotion in Java?

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.

Categories