28

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.

3
  • 4
    Thanks to all who answered. For anyone interested, section 5.2 of the language specification (Assignment Conversion) does in fact say "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." Commented Sep 10, 2010 at 9:09
  • 2
    If you, like me, happen to stumble on this because you want to know how to actually convert an indexed char into a string, here you go; when i=2 then String.valueOf((char)('a'+i)) returns the String "c". Commented Oct 23, 2013 at 23:01
  • The reason is that since char c is an unsigned integer is can only take positive values. The compiler is smart enough to understand that 'a' + 10 will never result in an illegal value therefore it compiles. where as the compiler evaluates 'a' + i in isolation and cant make out if this may result in a negatively signed or positive literal which may be illegal for char and therefore it will complain of lossy conversion. Commented Jul 30, 2023 at 8:31

6 Answers 6

21

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.

Sign up to request clarification or add additional context in comments.

3 Comments

char c = 65535; compiles, but not char c = 65536;
char is two bytes so this makes sense.
char c = 103000; does not. UCS-2 ftw!
12

'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.

2 Comments

Thanks. Looking up compile-time constant expression led me to the relevant section of the language specification.
char c = 'a' + 1L does not compile, This is wired
4

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)".

Comments

2

This code should works:

int i = 10;

char x = (char)('a' + i);

Comments

1

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.

1 Comment

I don't think it is quite correct to say that 10 is considered to be of type char. Rather, as Tom Hawtin says, the expression 'a' + 10 is a compile-time constant and therefore the compiler is allowed to do a narrowing conversion. Actually char c = 'a' + (char)i; does not work because the right-hand side is of type int and is not a compile-time constant.
0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.