If every operand in assignment and mathematical operations, before the expression performed, promote to int (if it doesn't have L, f, d flags);
And putting an int into a smaller primitive type (such as byte) should be done with narrow-casting;
So how the following assignment works?
byte a = 100;
If 100 is an integer, so putting it into a byte needs casting.
byte a = 100;
This works because...
If the right-hand side in an assignment context is a constant expression,
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.
Where
Literals of primitive type [...]
are a constant expression.
And the range of a byte is
[...] from -128 to 127, inclusive.
byte a = 100;
This works because byte range in java is from-128 to 127,so if you assign value upto 127,there is no need for cast.
Try to assign 128,you will get compiler error.
byte a = 128 ; //compiler error(incompatible type)
byte a = (byte)128;
It's a compile-time constant, and the compiler can determine that it'll fit in a byte. This actually did require a narrowing conversion in older versions of Java.
Related
Why don't we write s with short data type like short s = 2s; as we write with float e.g float f = 1.23f?
I know when we write float by default the compiler treats it as double and assigns 8 temporary bytes to it, and when it tries to copy that 8 byte to float's 4 that results in a type error, so that is why we write f after initializing a float, but why we don't do something similar with short as by default int is a literal type?
The Java Language Specification allows a type suffix of L or l for long literals. However, it does not provide a type suffix for short values. It's not necessary because:
Any value that could be represented by a short can also by represented by the default integral type int.
Assignments of an int value to a short variable are allowed if the value is a constant expression, whose value can be represented by a short. See the Java Language Specification, "Assignment Contexts":
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.
Why don't we add an “s” suffix to short types?
Because the Java language is inconsistent on this point.
The JLS is more flexible for no floating numeric primitive types as for floating numeric primitive types :
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.
I think that doing a distinction between byte, short, char, or int and float and double in the way to declare and manipulate them was not really required. It creates inconsistency and so potential mistakes in the use of them.
if short s = 10; is valid because the narrowing primitive conversion is validated by the compiler that it has no lost information, so float f = 10.0; would also have been valid for exactly the same reason.
That is because coming from double to a float is truncating value and losing data so the compiler doesn't do that automatically, you have to explicitly tell it. But when going from a smaller size, short, to a larger size, int, it is done automatically as the compiler just has to pad the data and there is no potential loss of data, as opposed to the former case.
If you declare variables of type byte or short and attempt to perform arithmetic operations on these, you receive the error "Type mismatch: cannot convert int to short" (or correspondingly "Type mismatch: cannot convert int to byte").
byte a = 23;
byte b = 34;
byte c = a + b;
In this example, the compile error is on the third line.
Although the arithmetic operators are defined to operate on any numeric type, according the Java language specification (5.6.2 Binary Numeric Promotion), operands of type byte and short are automatically promoted to int before being handed to the operators.
To perform arithmetic operations on variables of type byte or short, you must enclose the expression in parentheses (inside of which operations will be carried out as type int), and then cast the result back to the desired type.
byte a = 23;
byte b = 34;
byte c = (byte) (a + b);
Here's a follow-on question to the real Java gurus: why? The types byte and short are perfectly fine numeric types. Why does Java not allow direct arithmetic operations on these types? (The answer is not "loss of precision", as there is no apparent reason to convert to int in the first place.)
Update: jrudolph suggests that this behavior is based on the operations available in the JVM, specifically, that only full- and double-word operators are implemented. Hence, to operator on bytes and shorts, they must be converted to int.
The answer to your follow-up question is here:
operands of type byte and short are automatically promoted to int before being handed to the operators
So, in your example, a and b are both converted to an int before being handed to the + operator. The result of adding two ints together is also an int. Trying to then assign that int to a byte value causes the error because there is a potential loss of precision. By explicitly casting the result you are telling the compiler "I know what I am doing".
I think, the matter is, that the JVM supports only two types of stack values: word sized and double word sized.
Then they probably decided that they would need only one operation that works on word sized integers on the stack. So there's only iadd, imul and so on at bytecode level (and no operators for bytes and shorts).
So you get an int value as the result of these operations which Java can't safely convert back to the smaller byte and short data types. So they force you to cast to narrow the value back down to byte/short.
But in the end you are right: This behaviour is not consistent to the behaviour of ints, for example. You can without problem add two ints and get no error if the result overflows.
The Java language always promotes arguments of arithmetic operators to int, long, float or double. So take the expression:
a + b
where a and b are of type byte. This is shorthand for:
(int)a + (int)b
This expression is of type int. It clearly makes sense to give an error when assigning an int value to a byte variable.
Why would the language be defined in this way? Suppose a was 60 and b was 70, then a+b is -126 - integer overflow. As part of a more complicated expression that was expected to result in an int, this may become a difficult bug. Restrict use of byte and short to array storage, constants for file formats/network protocols and puzzlers.
There is an interesting recording from JavaPolis 2007. James Gosling is giving an example about how complicated unsigned arithmetic is (and why it isn't in Java). Josh Bloch points out that his example gives the wrong example under normal signed arithmetic too. For understandable arithmetic, we need arbitrary precision.
In Java Language Specification (5.6.2 Binary Numeric Promotion):
1 If any expression is of type double, then the promoted type is double, and other expressions that are not of type double undergo widening primitive conversion to double.
2 Otherwise, if any expression is of type float, then the promoted type is float, and other expressions that are not of type float undergo widening primitive conversion to float.
3 Otherwise, if any expression is of type long, then the promoted type is long, and other expressions that are not of type long undergo widening primitive conversion to long.
4 Otherwise, none of the expressions are of type double, float, or long. In this case, the promoted type is int, and any expressions that are not of type int undergo widening primitive conversion to int.
Your code belongs to case 4. variables a and b are both converted to an int before being handed to the + operator. The result of + operation is also of type int not byte
class A {
public static void main(String [] varun) {
byte b = 65;
char ch = b;
System.out.println(ch);
}
}
Why its give an error:
possible loss of precision
required char
found byte
The error text is misleading.
A char is a 2 byte unsigned type (range 0 to 65535)
A byte is a 1 byte signed type (range -128 to 127).
Therefore a byte cannot be represented in a char in full generality (as you'll lose the negatives). So you get an error; albeit a misleading one.
Byte is 1 byte long, while char is 2 bytes long, so they are incompatible. You need to use casting:
class A
{
public static void main(String [] varun)
{
byte b = 65;
char ch = (char) b;
System.out.println(ch);
}
}
Add as explicit cast as byte just take one byte and char is of two byte in java and implicit type cast does not work with byte and char.
Use
char ch = (char) b;
Your code should be like this:
char ch = (char) b;
The error it gave you it became from the fact that a byte type is an 8-bit integers and chars is 1-bit plus the bits of encoding (UTF-8, ASCII, etc).
The difference between a byte stream and a character stream is that the character stream attempts to work with characters rather than bytes.
So a byte stream is 8-bit stream without encoding. That's why you have this error.
If You are assigned two different type of primitives to each other You may have two types of casting:
if You assign int to long, thus putting smaller type into bigger You perform widening and so called widening conversion - it is also called implicit cast
int a = 100;
long b = a;
on the other hand if You would perform conversion from long to int You are narrowing the type. Thus You need to perform explicit cast if You don't do that You get that possible loss of precision
long a = 100L;
int b = (int)a;
or as in Your case as #Bathsheba said "Therefore a byte cannot be represented in a char in full generality (as you'll lose the negatives). So you get an error; albeit a misleading one." - You need to explicitly cast so that You are aware of loosing data.
When one type of data is assigned to another type of variable, an automatic type conversion
will take place if the following two conditions are met:
• The two types are compatible.
• The destination type is larger than the source type.
When these two conditions are met, a widening conversion takes place.
So the reason for it is,
For widening conversions, the numeric types, including integer and floating-point types,
are compatible with each other. However, there are no automatic conversions from the
numeric types to char or boolean.
The conversion from a byte to a char is a so-called Widening and Narrowing Primitive Conversion (JLS 5.1.4)
First, the byte is converted to an int via widening primitive conversion (§5.1.2), and then the resulting int is converted to a char by narrowing primitive conversion (§5.1.3).
The widening conversion from byte to int is fine (both are signed), but from int to char will loose both sign and (potentially) range (as char is 0 to 65536):
A narrowing primitive conversion may lose information about the overall magnitude of a numeric value and may also lose precision and range.
And
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.
Because of this potential loss of precision, sign and informaiton you get a compilation error and an explicit cast is necessary to signal to the compiler that you know what you're doing.
This may sound too trivial for an intermediate Java programmer. But during my process of reviewing Java fundamentals, found a question:
Why is narrowing conversion like:
byte b = 13;
will be allowed while
int i = 13;
byte b = i;
will be complained by the compiler?
Because byte b = 13 ; is assignment of a constant. Its value is known at compile time, so the compiler can/should/will whine if assignment of the constant's value would result in overflow (try byte b = 123456789 ; and see what happens.)
Once you assign it to a variable, you're assigning the value of an expression, which, while it may well be invariant, the compiler doesn't know that. That expression might result in overflow and so the compiler whines.
From here:
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. Assignment
contexts allow the use of an identity
conversion (§5.1.1), a widening
primitive conversion (§5.1.2), or a
widening reference conversion
(§5.1.4). In addition, a narrowing
primitive conversion may be used if
all of the following conditions are
satisfied:
The expression is a constant expression of type byte, short, char or int.
The type of the variable is byte, short, or char.
The value of the expression (which is known at compile time, because it is a constant expression) is representable in the type of the variable.
In your example all three conditions are satisfied, so the narrowing conversion is allowed.
P.S. I know the source I'm quoting is old, but this aspect of the language hasn't changed since.
Because a literal number has no type.
Once you give it a type it must be casted to the other one:
int i = 13;
byte b = (byte) i;
A byte has 8 bits. An int, 32 bits, and it is a signed number.
Conversion from a number with a smaller range of magnitude ( like int to long or long to float ) is called widening. The goal of widening conversions is to produce no change in the magnitude of the number while preserving as much of the precision as possible. For example, converting the int 2147483647 to float produces 2.14748365e9 or 2,147,483,650. The difference is usually small, but it may be significant.
Conversely, conversion where there is the possibility of losing information about the magnitude of the number ( like long to int or double to long ) is called narrowing. With narrowing conversions, some information may be lost, but the nearest representation is found whenever possible. For example, converting the float 3.0e19 to long yields -9223372036854775807, a very different number.
If you declare variables of type byte or short and attempt to perform arithmetic operations on these, you receive the error "Type mismatch: cannot convert int to short" (or correspondingly "Type mismatch: cannot convert int to byte").
byte a = 23;
byte b = 34;
byte c = a + b;
In this example, the compile error is on the third line.
Although the arithmetic operators are defined to operate on any numeric type, according the Java language specification (5.6.2 Binary Numeric Promotion), operands of type byte and short are automatically promoted to int before being handed to the operators.
To perform arithmetic operations on variables of type byte or short, you must enclose the expression in parentheses (inside of which operations will be carried out as type int), and then cast the result back to the desired type.
byte a = 23;
byte b = 34;
byte c = (byte) (a + b);
Here's a follow-on question to the real Java gurus: why? The types byte and short are perfectly fine numeric types. Why does Java not allow direct arithmetic operations on these types? (The answer is not "loss of precision", as there is no apparent reason to convert to int in the first place.)
Update: jrudolph suggests that this behavior is based on the operations available in the JVM, specifically, that only full- and double-word operators are implemented. Hence, to operator on bytes and shorts, they must be converted to int.
The answer to your follow-up question is here:
operands of type byte and short are automatically promoted to int before being handed to the operators
So, in your example, a and b are both converted to an int before being handed to the + operator. The result of adding two ints together is also an int. Trying to then assign that int to a byte value causes the error because there is a potential loss of precision. By explicitly casting the result you are telling the compiler "I know what I am doing".
I think, the matter is, that the JVM supports only two types of stack values: word sized and double word sized.
Then they probably decided that they would need only one operation that works on word sized integers on the stack. So there's only iadd, imul and so on at bytecode level (and no operators for bytes and shorts).
So you get an int value as the result of these operations which Java can't safely convert back to the smaller byte and short data types. So they force you to cast to narrow the value back down to byte/short.
But in the end you are right: This behaviour is not consistent to the behaviour of ints, for example. You can without problem add two ints and get no error if the result overflows.
The Java language always promotes arguments of arithmetic operators to int, long, float or double. So take the expression:
a + b
where a and b are of type byte. This is shorthand for:
(int)a + (int)b
This expression is of type int. It clearly makes sense to give an error when assigning an int value to a byte variable.
Why would the language be defined in this way? Suppose a was 60 and b was 70, then a+b is -126 - integer overflow. As part of a more complicated expression that was expected to result in an int, this may become a difficult bug. Restrict use of byte and short to array storage, constants for file formats/network protocols and puzzlers.
There is an interesting recording from JavaPolis 2007. James Gosling is giving an example about how complicated unsigned arithmetic is (and why it isn't in Java). Josh Bloch points out that his example gives the wrong example under normal signed arithmetic too. For understandable arithmetic, we need arbitrary precision.
In Java Language Specification (5.6.2 Binary Numeric Promotion):
1 If any expression is of type double, then the promoted type is double, and other expressions that are not of type double undergo widening primitive conversion to double.
2 Otherwise, if any expression is of type float, then the promoted type is float, and other expressions that are not of type float undergo widening primitive conversion to float.
3 Otherwise, if any expression is of type long, then the promoted type is long, and other expressions that are not of type long undergo widening primitive conversion to long.
4 Otherwise, none of the expressions are of type double, float, or long. In this case, the promoted type is int, and any expressions that are not of type int undergo widening primitive conversion to int.
Your code belongs to case 4. variables a and b are both converted to an int before being handed to the + operator. The result of + operation is also of type int not byte