47

In Java, the following is allowed:

char c = 'A' + 1;

Here, c will hold the value 'B'. Above, first the expression is evaluated. So 'A' gets converted to 65, the whole expression evaluates to 66, and then 66 is converted to 'B' since we are storing the value in a char.

The following, however, gives a compile-time error:

char c = 'A';
c = c + 1;

What is the explanation for how Java views the expressions differently? By the way, the following works fine too:

char c = 'A';
c++;
Radiodef
  • 37,180
  • 14
  • 90
  • 125
Cosmic_Dust
  • 471
  • 1
  • 4
  • 6
  • 2
    Please have a look at the following question and specfically at rgettman's answer: http://stackoverflow.com/questions/18648283/why-doesnt-a-character-increment-in-system-out-println – bblincoe Jan 23 '14 at 19:37
  • I'm not sure if saying that 66 is converted to 'B' is a precise saying. Characters are basically numerals already. – Piovezan Jan 23 '14 at 19:54
  • 1
    @Piovezan That's an interesting point though the [spec does describe char as a range of code points](http://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.2.1) as well as the integral range. For literals, a character literal ('B') is always of type char and of course 66 is always of type int. Perhaps the most precise would be to say it is converted to '\u0042' (a numerical code that's always of type char). – Radiodef Jan 23 '14 at 20:12
  • This is a nice question , I didn't see as like it before. Awesome question. And your accepted answer also great and completed for yours. – Cataclysm Jan 24 '14 at 02:51
  • By the way, `char` is a legacy type, essentially broken since Java 2. As a 16-bit value, `char` is physically incapable of representing most characters. Instead, learn to use [code point](https://en.wikipedia.org/wiki/Code_point) integer numbers when working with individual characters. You'll find code point related methods across various classes including `String`, `StringBuilder`, `Character`, etc. – Basil Bourque Jan 07 '23 at 01:45

4 Answers4

43

The first example (which compiles) is special because both operands of the addition are literals.

A few definitions to start with:

  • Converting an int to char is called a narrowing primitive conversion, because char is a smaller type than int.

  • 'A' + 1 is a constant expression. A constant expression is (basically) an expression whose result is always the same and can be determined at compile-time. In particular, 'A' + 1 is a constant expression because the operands of + are both literals.

A narrowing conversion is allowed during the assignments of byte, short and char, if the right-hand side of the assignment is a constant expression:

In addition, if the expression [on the right-hand side] 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.

c + 1 is not a constant expression, because c is a non-final variable, so a compile-time error occurs for the assignment. From looking at the code, we can determine that the result is always the same, but the compiler isn't allowed to do that in this case.

One interesting thing we can do is this:

final char a = 'a';
char b = a + 1;

In that case a + 1 is a constant expression, because a is a final variable which is initialized with a constant expression.

The caveat "if […] the value […] is representable in the type of the variable" means that the following would not compile:

char c = 'A' + 99999;

The value of 'A' + 99999 (which is 100064, or 0x186E0) is too big to fit in to a char, because char is an unsigned 16-bit integer.


As for the postfix ++ operator:

The type of the postfix increment expression is the type of the variable.

...

Before the addition, binary numeric promotion* is performed on the value 1 and the value of the variable. If necessary, the sum is narrowed by a narrowing primitive conversion and/or subjected to boxing conversion to the type of the variable before it is stored.

(* Binary numeric promotion takes byte, short and char operands of operators such as + and converts them to int or some other larger type. Java doesn't do arithmetic on integral types smaller than int.)

In other words, the statement c++; is mostly equivalent to:

c = (char)(c + 1);

(The difference is that the result of the expression c++, if we assigned it to something, is the value of c before the increment.)

The other increments and decrements have very similar specifications.

Compound assignment operators such as += automatically perform narrowing conversion as well, so expressions such as c += 1 (or even c += 3.14) are also allowed.

Community
  • 1
  • 1
Radiodef
  • 37,180
  • 14
  • 90
  • 125
  • I guess the reason Java applies this rule is because (as Brian said) Java can't decide if the integer would be in the range. – Cosmic_Dust Jan 23 '14 at 21:20
  • Yeah basically. A narrowing conversion implies there could be overflow and Java wants that possibility to be explicit. You can always do something like `char c = (char)('A' + 99999);`. – Radiodef Jan 23 '14 at 21:32
4

char to int conversion is called widening conversions. In widening conversions, values do not lose information about the overall magnitude of a numeric value where as int to char conversion is called narrowing conversions. With narrowing conversion you may lose information about the overall magnitude of a numeric value and may also lose precision.

For more information on primitive conversions refer this document.

RMachnik
  • 3,598
  • 1
  • 34
  • 51
4

It is because the compiler can check that it ('A' + 1) is within the bounds of a char whereas it cannot (in general) check that c + <an integer> is within the bounds.

Engineer2021
  • 3,288
  • 6
  • 29
  • 51
0

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 when you perform

   c= c+1;//compiler error

Its the result of c+1 is int not a char . so compiler give a compile time error for the same. so you need to provide a primitive cast to change the literal to char data type. Hope this example provide some understanding..

vinod bazari
  • 210
  • 1
  • 2
  • 10