what is the difference between '1' - 0 and '1' - '0' [duplicate] - java

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.

Related

Error occured when assign int to char [duplicate]

You cannot convert from int to char, so this would be illegal
int i = 88; char c = i;,
However this is allowed char c = 88;.
Isn't a plain number and int literal? How is this allowed?
char is effectively an unsigned 16-bit integer type in Java.
Like other integer types, you can perform an assignment conversion from an integer constant to any integer type so long as it's in the appropriate range. That's why
byte b = 10;
works too.
From the JLS, section 5.2:
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.
Actually, converting from int to char is legal, it just requires an explicit cast because it can potentially lose data:
int i = 88;
char c = (char) i;
However, with the literal, the compiler knows whether it will fit into a char without losing data and only complains when you use a literal that is too big to fit into a char:
char c = 70000; // compiler error
Its because the literals for integer or smaller than int as byte ,short and char is int. Understand the following in this way.
code:
byte a = 10;//compile fine
byte b= 11;//compile fine
byte c = a+b;//compiler error[says that result of **a+b** is **int**]
the same happens for any mathematical operations as of 'Divide', 'multiply', and other arithmetic operation. so cast the result to get the literal in desired data type
byte c = (byte)(a+b);
So that the same reason why the value int need to have primitive cast to change the value in char.
Hope this make some sense.

Implicit variable casting

How come this,
char ch = 9 + '0';
System.out.println(ch);
Will result in,
9
But,
int k = 9;
char ch = k + '0';
System.out.println(ch);
will return
"Type mismatch: cannot convert from int to char"
This is described in JLS Sec 5.2:
5.2 Assignment Contexts
...
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.
...
Example: The compile-time narrowing of constant expressions means that code such as:
byte theAnswer = 42;
is allowed.
This applies to your example because 9 + '0' is a constant, and it can be statically determined that it fits into a char. As such, the cast can be done implicitly.
On the other hand, k is not constant, so the compiler can't know for sure that k + '0' will fit into char; hence, it requires an explicit cast.
The compiler knows that 9 + '0' is 57, which fits into a 16-bit char value. The compiler does not keep track of variable assignments (except for static final constants) so it cannot be certain that k + '0' evaluates to a value that fits in 16 bits.
That 16-bit size limitation is also why you will also get the same compiler error for this:
char ch = 10_000_000 + '0';
When using 9 + '0', compiler uses ASCII value of character and adds it to the literal (9) value and then converts it back to the char
i.e.
9 + 48 = 57
57 ACII -->= '9' (char)
When using k + '0'
k is declared as int and '0' is char. Compiler wont compile here as they are different types and target is smaller to accommodate the resultant value.

Why no explicit casting is required while assigning int to char [duplicate]

I wanted to know why this snippet works.
char ch1;
ch1 = 'a' + 1;
System.out.println(ch1);
In line 2, isn't the right hand side promoted to an int and then for assigning int to char, won't we need an explicit cast?
Similarly, I understand what happens when you do ch1 = 65. But since Java does not allow automatic down type conversion, don't we need explicit cast from int to char?
Because the Java Language 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.
So you're right in that the expression is promoted to int, but because it's a constant expression, the cast is not necessary. If it involved a variable (or its value did not fit into a char), it would be different.
For this kind of question it's best to look at the language specification right away, as it's the authoritative source and quite readable for a specification.
I'm using Eclipse at the moment. There are two things to note:
The compiler checks for bounds during initialization.
The compiler calculates the values of constant expressions, such as 3 * (2 + 1).
This works:
byte b = 127; // works, range of a byte is [-128, 127]
But this does not:
byte b = 128; // does not work, outside of range
This works:
byte b = 100 + -228; // works, 100 + -228 = -128
But this does not:
byte b = 1;
byte c = b + 1; // does not work, why not?
And this does not, either:
byte b = 1;
byte c = b + (byte) 1; // does not work, why not?
Note that b is a variable expression. If a variable expression is involved, the result of the operator + is at least as large as an int. Therefore, you can't assign it to c. Unlike constant expressions, the compiler does not calculate variable expressions.
The compiler would similarly complain for short and char - try it out yourself.
And finally, using final on a variable effectively turns it into a constant expression, so this would work:
final byte b = 1;
byte c = b + 1; // works

Java char is also an int?

I was trying to get some code done for class:
public int getValue(char value) {
if (value == 'y') return this.y;
else if (value == 'x') return this.x;
Since I might not be able to return anything in the end, it told me to do this at the end:
return value;
This surprised me because the return type for the method was of type int. Yet, it was telling me to return a char! I'm using eclipse, and accustomed to the endless number of warnings and stuff, this was a major surprise.
So, is a char really an int? Why is this happening?
The Java Language Specification states
When a return statement with an Expression appears in a method
declaration, the Expression must be assignable (§5.2) to the declared
return type of the method, or a compile-time error occurs.
where the rules governing whether one value is assignable to another is defined as
Assignment contexts allow the use of one of the following:
a widening primitive conversion (§5.1.2)
and
19 specific conversions on primitive types are called the widening
primitive conversions:
char to int, long, float, or `double
and finally
A widening primitive conversion does not lose information about the
overall magnitude of a numeric value in the following cases, where the
numeric value is preserved exactly: [...]
A widening conversion of a char to an integral type T zero-extends the
representation of the char value to fill the wider format.
In short, a char value as the expression of a return statement is assignable to a return type of int through widening primitive conversion.
A char is smaller than an int, so you can return it and it will prepend zeroes to make a longer number. That's not the right thing to return - in your case I'd probably throw an exception instead; however, the editor suggested it because it's something that you're allowed to return and you need to return something.
The following code is legal:
char c = 'h';
int i = c;
In computing, everything is numbers! Just bits and bytes.
int, char, byte, short and long are just numbers. A char is just a number that the compiler knows is usually used for displaying the character represented by the particular number (e.g. 32 = space, 48 = zero, etc).
A String is a sequence of numbers and other stuff, so a bit more complicated. We don't want to go there.
An int is a four byte number and a char is a two byte number, so you can fit any char number in an int.
The designers of Java just decided they would let you convert from char to int without requiring any special casts or conversions.
A char is not an int. However, it is an integral type. That is to say, it's considered to be a whole number that can be converted to and from other integral types (long,short,byte and int), according to the Java Language Specification.
Basically what this means is that it is assignment-compatible to int. Its value is between 0 and 65535, and if you assign it to an int or cast it to an int and print it, you'll get the UTF-16 value of the character it represents.
By definition (in java) a char is an 8bit unsigned integer. (0 to 256)
An int an 32bit signed integer. (−2.147.483.648 to 2.147.483.647)
char a = 65; //65 is the ASCII Number of 'A'
System.out.println(a);
>>> A
b = a + 1
System.out.println(b);
>>> B
java autoboxing converts char to int and vice versa
There is an implicit and natural conversion from int to char and vice-versa. Note that you thus have the usual arithmetic defined on charm which comes very handy when you want, let's say, to iterate on the alphabet :
for (char c='a' ; c<='z' ; c++) { ... }
However, note that a char is 2 bytes long whereas an int is 4 bytes long, so casting an int down to a char may result in an integer overflow.
Hope this little example solves your confusion:
public int getValue(int value) {
if (value == 'y')
return this.y;
else if (value == 'x')
return this.x;
}
If you pass char as an int like getValue('x'), it would return the value of the int.

Why can I assign an int to a char variable without an explicit cast?

I wanted to know why this snippet works.
char ch1;
ch1 = 'a' + 1;
System.out.println(ch1);
In line 2, isn't the right hand side promoted to an int and then for assigning int to char, won't we need an explicit cast?
Similarly, I understand what happens when you do ch1 = 65. But since Java does not allow automatic down type conversion, don't we need explicit cast from int to char?
Because the Java Language 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.
So you're right in that the expression is promoted to int, but because it's a constant expression, the cast is not necessary. If it involved a variable (or its value did not fit into a char), it would be different.
For this kind of question it's best to look at the language specification right away, as it's the authoritative source and quite readable for a specification.
I'm using Eclipse at the moment. There are two things to note:
The compiler checks for bounds during initialization.
The compiler calculates the values of constant expressions, such as 3 * (2 + 1).
This works:
byte b = 127; // works, range of a byte is [-128, 127]
But this does not:
byte b = 128; // does not work, outside of range
This works:
byte b = 100 + -228; // works, 100 + -228 = -128
But this does not:
byte b = 1;
byte c = b + 1; // does not work, why not?
And this does not, either:
byte b = 1;
byte c = b + (byte) 1; // does not work, why not?
Note that b is a variable expression. If a variable expression is involved, the result of the operator + is at least as large as an int. Therefore, you can't assign it to c. Unlike constant expressions, the compiler does not calculate variable expressions.
The compiler would similarly complain for short and char - try it out yourself.
And finally, using final on a variable effectively turns it into a constant expression, so this would work:
final byte b = 1;
byte c = b + 1; // works

Categories

Resources