This question already has answers here:
Why can not I add two bytes and get an int and I can add two final bytes get a byte?
(3 answers)
Java - char, int conversions
(4 answers)
Closed 8 years ago.
The following segment of code issues a compile-time error.
char c = 'c';
char d = c + 5;
The error on the second line says,
possible loss of precision
required: char
found: int
The error message is based on the NetBeans IDE.
When this character c is declared final like as follows.
final char c = 'c';
char d = c + 5;
The compiler-time error vanishes.
It is unrelated to the case of final strings
What does the final modifier make a difference here?
The reason is that the JLS #5.2 (Assignment conversion) says so:
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.
In your example, char c = 'c'; is not a constant but final char c = 'c'; is.
The rationale is probably that the addition operator + first converts its operands to integers. So the operation could overflow unless everything is constant in which case the compiler can prove that there is no overflow.
When you apply the + operator to integral types
Binary numeric promotion is performed on the operands (§5.6.2).
In this case, the char values are promoted to int values.
Here
char c = 'c';
char d = c + 5;
because c is not a constant expression, the compiler cannot determine if the value of c + 5 which is an int will be able to fit in a char.
In this
final char c = 'c';
char d = c + 5;
where c is a constant expression, the compiler can determine that the value of c, which is 99, added to 5, which is 104 does fit in a char. Because of this guarantee, Java can safely perform a narrowing conversion from int to char.
If instead you had
final char a = Character.MAX_VALUE;
char b = (a + 5);
you would see the similar behavior as your first test case as the value of a + 5 does not fit in a char. The compiler determines that the int value resulting from a + 5 would not fit in a char.
Related
This question already has answers here:
Why can't you add an int and a char in some cases?
(1 answer)
Java - char, int conversions
(4 answers)
Integer arithmetic in Java with char and integer literal
(6 answers)
Closed 1 year ago.
Why can't i do this?
public class test123 {
public static void main (String [] args) {
char c = 34;
char a = c + 10;
}
}
new to java, so sorry if this question is actually stupid.
When you add numbers, they undergo binary numeric promotion. That is, the operands are widened to allow them to be added.
When you add a char to an int, the char is widened to an int, and the result is an int.
As such, you would have to cast the int back to a char:
char a = (char) (c + 10);
However, even when adding a char to another char, both are widened to int, and the result is again an int, and so cannot be assigned to a char variable. The rules are basically:
If either operand is a double, widen both to double
Else, if either operand is a float, widen both to float
Else, if either operand is a long, widen both to long
Else, widen both to int
So, even if you were adding a byte to a byte, both are widened to int, added, and the result is an int.
The exception to this is if you made c final:
final char c = 34;
In that case, c has a compile-time constant value, so c + 10 is a compile-time constant expression. Because it's a compile-time constant expression, the compiler knows its value, and knows that it fits into the range of char; so it would be allowed:
final char c = 34;
char a = c + 10;
As per the JLS, int is the narrowest type for arithmetic. Narrower values are widened to int, and the result is int.
You would get the same error even if you coded:
char a = c + c; // error
The Java char is a primitive data type. It is used to declare the character-type like char char1='a';
But you can add an int to a char, but the result is an int - you'd have to cast back to char
char a = 'a';
char b = (char)(a+4);
System.out.println(b);// print "e"
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
Have a look at the following code :
Case 1 :
char a = 'x' ^ 'y';
It is working fine.
But when I use variable instead of constants as here :
Case 2:
char x = 'x';
char y = 'y';
char a = x ^ y; // Error!
In java language : case 1 is working and value of a comes out to be 1 but case 2 is not working.
In C and C++ : both cases are working, and the value of a comes out to be 1
In C# : both the cases are not working.
In javascript : both cases are working, which is not a HLL, and value of a comes out to be 0.
I understand that java is converting variables to integer to do binary operation, but why it is working in case 1 and not in case 2, Why same is not working in C# And why the values are different in the case of javascript.
Updated
When I made the variables final than it is working in java, but still not in C#
final char x = 'x';
final char y = 'y';
char a = x ^ y;
But still I cannot understand why constants are working but when using variable they are not. And why same is not happening with other high level programming language.
I think it is a basic operation and should be working in all programming languages with same behaviour.
Note To test all above cases in javascript I am replacing 'char' with 'var' in all cases and they are working.
Answering for Java only.
The expression 'x' ^ 'y' is a constant expression; x ^ y is not, unless both variables are declared final. Furthermore, the result is an int; ^ is an integral bitwise operator, meaning that both operands have to be promoted to an integral type before being evaluated. char promotes to int.
So you have this int expression, and you try to narrow it to a char. In the general case, this could lead to a loss of precision (ints are 4 bytes, chars are 2), so the compiler doesn't let you do that without you explicitly stating it's what you want to do (via a cast to char). However, you can implicitly narrow constant expressions, if their value would fit into the new type. From JLS 5.2:
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.
(Emphasis added)
Intuitively, this makes total sense: the error is there to tell you that you may lose precision, and so it wants you to confirm that you know that; in a sense, it's a loud warning. But if the compiler can know absolutely that this won't happen, as it can for a constant expression, then it makes things a bit easier for you and "hides" that warning.
I will consider C languages that is C, C++ and C#.
In C# there is no implicit conversion from an integral type to type char. According to section "11.1.5 Integral types" of the ECMA 334 Standard "C# Specification"
• There are no implicit conversions from other types to the char type.
In particular, even though the sbyte, byte, and ushort types have
ranges of values that are fully representable using the char type,
implicit conversions from sbyte, byte, or ushort to char do not exist.
So you need explicitly to cast the result of the operator to type char. For example
using System;
namespace ExclusiveOr
{
class Program
{
static void Main(string[] args)
{
char a = ( char )('x' ^ 'y' );
char c = 'x', d = 'y';
char b = ( char )( c ^ d );
Console.WriteLine("a = {0}, b = {1}", (int)a, (int)b);
}
}
}
The output is
a = 1, b = 1
According to the C Standard (section 6.7.9 Initialization)
4 All the expressions in an initializer for an object that has static
or thread storage duration shall be constant expressions or string
literals
So for example this code will be compiled
#include <stdio.h>
char a = 'x' ^ 'y';
int main(void)
{
printf( "a = %d\n", a );
return 0;
}
The output is
a = 1
However this code will not be compiled
#include <stdio.h>
char c = 'x';
char d = 'y';
char b = c ^ d;
int main(void)
{
printf( "b = %d\n", b );
return 0;
}
will not be compiled. The GCC compiler will issue error
prog.c:8:1: error: initializer element is not constant char b = c ^ d;
However if you will make varaible b local then the code will be compiled successfully
#include <stdio.h>
char c = 'x';
char d = 'y';
int main(void)
{
char b = c ^ d;
printf( "b = %d\n", b );
return 0;
}
The output is
b = 1
In C++ there is no such a restriction for objects with the static storage duration so all examples of programs similar to C programs showed above will be compiled.
Under normal circumstances, the operands of the following binary operators are "widened" before the operation is performed.
(From the JLS 5.6.1)
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)
In the case of char operands, widening will convert the operands to int.
For the arithmetic and bitwise operations, the type of the operation's result is the same as the "wider" of the two operands.
When x and y have type char, the expression x ^ y gives you an int value. That can't be assigned back to a char without a type cast, and hence you get a compilation error.
For the case where you are using char literals, the same widening process happens. But there is a "special exception" in the language which allows the value of a constant expression to be implicitly narrowed, provided that the constant expression's value will fit into the type. In this case, 'x' ^ 'y' will "fit" into a char, so the assignment is allowed.
The JLS reference for this exception for constant expressions is JLS 5.2.
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.
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.