I'm seeing both char and short are two bytes each,
also the following is valid:
char a = 'x';
int b = a;
long c = a;
However when I do short d = a; I'm getting an error that cannot convert from char to short.
even though both are two bytes.
One use of char I can see is when you print it, it displays the character. Is that the only use of char?
In Java the data type char is an unsigned 2 byte variable while a short is signed 2 byte variable. Because of this difference you cannot convert a char to a short because a char has that extra bit that isn't the signed bit.
This means that if you convert char to a short you would have to truncate the char which would cause the complaining.
You should probably want to read about data types and type casting to have a clear understanding.
When you tried to do short d=a; you are trying to do the 'Narrowing Primitive Conversion'.
5.1.3 Narrowing Primitive Conversions
The following 22 specific conversions
on primitive types are called the
narrowing primitive conversions:
short to byte or char
char to byte or short
int to byte, short, or char
long to byte, short, char, or int
float to byte, short, char, int, or long
double to byte, short, char, int, long, or float
Narrowing conversions may lose
information about the overall
magnitude of a numeric value and may
also lose precision.
While it is true that char is an unsigned 16-bit type, it is not designed to be used as such. Conceptually, char is a Unicode character (more precisely, a character from the Unicode subset that can be represented with 16 bits in UTF-16) which is something more abstract than just a number. You should only ever use chars for text characters. I think that making it an integer type is a kind of bad design on Java's side. It shouldn't have allowed any conversions between char and integer types except by using special utility methods. Like boolean is impossible to convert to integers and back.
char is generally only used for text, yes.
char is unsigned, while short is signed.
check out the Java Docs
it's all there... Char and Short aren't the same.
Normally, I use char for text, and short for numbers. (If I use short. I'd rather use int/long when they're available).
You may want to "cast" the variable. It's done like this:
char a = 'x';
short sVar = (short)a;
System.out.println(a);
System.out.println(sVar);
char is a Unicode-character and, therefore, must be unsigned. short is like all other numeric primitive types signed. Therefore, short and char cover two different ranges of values causing the compiler to complain about the assignment.
Related
Why is char c = (char)65.8; allowed in Java?
Shouldn't it throw an error since 65.8 is not an exact Unicode value? I understand that the double is truncated to an integer, in this case, 65, but it seems like bad design to me to allow the programmer to make such a cast.
That is called Narrowing type casting.
From oracle docs:
22 specific conversions on primitive types are called the narrowing
primitive conversions:
short to byte or char
char to byte or short
int to byte, short, or char
long to byte, short, char, or int
float to byte, short, char, int, or long
double to byte, short, char, int, long, or float
A narrowing primitive conversion may lose information about the
overall magnitude of a numeric value and may also lose precision and
range.
In Java, there are two basic types of type conversions: widening and narrowing.
A widening conversion occurs when you convert from a type with smaller (or narrower) to type with larger (or wider) range. Because of this, there is no chance for data loss and the conversion is considered "safe."
A narrowing conversion occurs when you convert from a type with larger (or wider) to type with smaller (or narrower) range. Since we are shrinking the range, there is a chance of data loss so this conversion is considered "unsafe"
The conversion from byte to char is a special case and represents widening and narrowing at the same time. The conversion starts by converting the byte to an int and then the int gets converted to the char.
One reason I can think of why narrowing type casting doesn't result in an error/exception is to allow for a convenient/easy/quick type conversion in the cases when no data will be loss. Compiler leaves it up to us to make sure converted data will be able to fit in the smaller range. It is also useful if we want to quickly truncate values such as rounding the value of a double (by type-casting it to an int).
it doesn't happen automatically on assignment: that would be a compilation error.
The fact that the programmer makes a conscious choice (e.g. the type cast) means she is taking into consideration the possibility of, and responsibility for, possible truncation.
You may have code such as cipher algorithms that may find useful to cast a double or float to char. Also, char is an unsigned type, which means (char)200.5 yields something different than (char)(byte)200.5.
How can the dumb computer know what was intended?
char c = (char)65.8; // valid, double gets converted and explicitly truncated to a char
It may so happen that during a calculation, you might be doing some complex computations involving double arithmetic and finally on the final value, you apply the trucation and display as a character. What's wrong?
This question already has answers here:
short and char type in Java [duplicate]
(2 answers)
Why is casting to short to char is a narrowing conversion?
(2 answers)
Closed 5 years ago.
Why can we not pass a char value as an argument to any method that accepts a short parameter, whereas we can pass a char value to another method whose parameter is of int type? Why does type casting not take place from char to short, given that the sizes are equal? I hope short can also store as much values as short can.
Why can we not pass a char value as a argument to any method that accepts a short parameter
Because there's no implicit conversion from char to short in an invocation context.
whereas we can pass a char value to another method whose parameter is of int type?
That's because there is an implicit conversion available from char to int in an invocation context.
Why does type casting not take place from char to short, given that the sizes are equal? I hope short can also store as much values as short can.
Although char and short are the same size, char is unsigned whereas short is signed. That's why there's no implicit conversion from char to short.
The conversion from char toint is a widening primitive conversion (JLS 5.1.2) whereas the conversion from char to short is a narrowing primitive conversion (JLS 5.1.3). In particular (emphasis mine):
A narrowing conversion of a char to an integral type T likewise 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 resulting value to be a negative number, even though chars represent 16-bit unsigned integer values.
Java specification says:
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.
Char has a minimum value of 0 and a maximum value of 65,535.
Short has a minimum value of -32,768 and a maximum value of 32,767.
Integer has a minimum value of -2,147,483,648 and a maximum value of 2,147,483,647.
So char can fit into integer but not into short, that's why you should assure java that you want to do typecast here.
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.
How come this happens:
char a = '\uffff'; //Highest value that char can take - 65535
byte b = (byte)a; //Casting a 16-bit value into 8-bit data type...! Isn't data lost here?
char c = (char)b; //Let's get the value back
int d = (int)c;
System.out.println(d); //65535... how?
Basically, I saw that a char is 16-bit. Therefore, if you cast it into a byte, how come no data is lost? (Value is the same after casting into an int)
Thanks in advance for answering this little ignorant question of mine. :P
EDIT: Woah, found out that my original output actually did as expected, but I just updated the code above. Basically, a character is cast into a byte and then cast back into a char, and its original, 2-byte value is retained. How does this happen?
As trojanfoe states, your confusion on the results of your code is partly due to sign-extension. I'll try to add a more detailed explanation that may help with your confusion.
char a = '\uffff';
byte b = (byte)a; // b = 0xFF
As you noted, this DOES result in the loss of information. This is considered a narrowing conversion. Converting a char to a byte "simply discards all but the n lowest order bits".
The result is: 0xFFFF -> 0xFF
char c = (char)b; // c = 0xFFFF
Converting a byte to a char is considered a special conversion. It actually performs TWO conversions. First, the byte is SIGN-extended (the new high order bits are copied from the old sign bit) to an int (a normal widening conversion). Second, the int is converted to a char with a narrowing conversion.
The result is: 0xFF -> 0xFFFFFFFF -> 0xFFFF
int d = (int)c; // d = 0x0000FFFF
Converting a char to an int is considered a widening conversion. When a char type is widened to an integral type, it is ZERO-extended (the new high order bits are set to 0).
The result is: 0xFFFF -> 0x0000FFFF. When printed, this will give you 65535.
The three links I provided are the official Java Language Specification details on primitive type conversions. I HIGHLY recommend you take a look. They are not terribly verbose (and in this case relatively straightforward). It details exactly what java will do behind the scenes with type conversions. This is a common area of misunderstanding for many developers. Post a comment if you are still confused with any step.
It's sign extension. Try \u1234 instead of \uffff and see what happens.
java byte is signed. it's counter intuitive. in almost all situations where a byte is used, programmers would want an unsigned byte instead. it's extremely likely a bug if a byte is cast to int directly.
This does the intended conversion correctly in almost all programs:
int c = 0xff & b ;
Empirically, the choice of signed byte is a mistake.
Some rather strange stuff going on your machine. Take a look at Java language specification, chapter 4.2.1:
The values of the integral types are
integers in the following ranges:
For byte, from -128 to 127, inclusive
... snip others...
If your JVM is standards compliant, then your output should be -1.