Java - char和int之间的转换

47

在Java中,以下内容是允许的:

char c = 'A' + 1;

在这里,c将保存值'B'。首先,表达式将被评估。因此'A'被转换为65,整个表达式评估为66,然后由于我们将值存储在char中,66被转换为'B'。

然而,以下代码将产生编译时错误:

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

Java是如何解释表达式的差异的?顺便说一句,以下代码也可以正常工作:

char c = 'A';
c++;

2
请查看以下问题,特别是rgattman的答案:http://stackoverflow.com/questions/18648283/why-doesnt-a-character-increment-in-system-out-println - bblincoe
我不确定说66被转换为'B'是一个准确的说法。字符基本上已经是数字了。 - Piovezan
1
@Piovezan 这是一个有趣的观点,尽管规范确实将char描述为一系列代码点,以及整数范围。对于字面量,字符字面量('B')始终是char类型,当然66始终是int类型。也许最精确的说法是将其转换为'\u0042'(始终是char类型的数字代码)。 - Radiodef
这是一个很好的问题,我以前没有见过类似的。非常棒的问题。而且你接受的答案也很棒,完全符合你的需求。 - Cataclysm
顺便提一下,char 是一个遗留类型,自 Java 2 以来基本上已经失效。作为一个 16 位值,char 在物理上无法表示大多数字符。相反,当处理单个字符时,请学习使用 代码点 整数。您将在各种类中找到与代码点相关的方法,包括 StringStringBuilderCharacter 等。 - Basil Bourque
4个回答

43

第一个例子(可以编译)很特殊,因为加法的两个操作数都是字面量。

首先需要了解一些定义:

  • int转换为char称为缩小原始类型转换,因为charint更小。

  • 'A' + 1是一个常量表达式。 常量表达式是(基本上)其结果始终相同且可以在编译时确定的表达式。 特别地,'A' + 1是一个常量表达式,因为+的操作数都是字面量。

在赋值时,允许对byteshortchar进行缩窄转换,如果赋值右侧为常量表达式

此外,如果表达式[在赋值右侧]是byteshortcharint类型的常量表达式:

  • 如果变量是byteshortchar类型,并且常量表达式的值可以用该变量的类型表示,则可以使用缩窄原始转换。

c + 1不是常量表达式,因为c是一个非final变量,所以会出现编译时错误。从代码上看,我们可以确定结果总是相同的,但编译器在这种情况下不被允许这样做。

我们可以做的一件有趣的事情是这样的:

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

在这种情况下,a + 1是一个常量表达式,因为a是一个用常量表达式初始化的final变量。
“如果[...]值[...]在变量的类型中可表示”这个警告意味着以下内容将无法编译:
char c = 'A' + 99999;

"

'A' + 99999的值(即1000640x186E0)太大了,无法放入char中,因为char是一个无符号16位整数

"

关于后缀++运算符

后缀递增表达式的类型是变量的类型。

...

在添加之前,对值1和变量的值执行二进制数值提升*。 如果需要,将通过缩小原始转换来缩小总和,并/或将其转换为变量的类型进行装箱转换,然后再存储。

(* 二进制数值提升将操作数(如+)的byteshortchar转换为int或其他更大的类型。Java不对小于int的整数类型进行算术运算。)

换句话说,语句c++;大多等效于:

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.)
其他的增减运算也有非常相似的规定。 复合赋值运算符例如+=也会自动进行缩小转换, 因此像c += 1(甚至c += 3.14)这样的表达式也是允许的。

我猜Java应用这个规则的原因是因为(正如Brian所说)Java无法确定整数是否在范围内。 - Cosmic_Dust
基本上是这样的。窄化转换意味着可能会溢出,Java希望这种可能性是明确的。你可以像这样做:char c = (char)('A' + 99999); - Radiodef

4

将字符转换为整数被称为扩展转换。在扩展转换中,值不会丢失关于数字值总大小的信息,而将整数转换为字符被称为缩小转换。使用缩小转换,您可能会失去有关数字值总大小的信息,并可能损失精度。

有关基本转换的更多信息,请参阅此文档


4

编译器之所以可以检查('A' + 1)是否在char类型的范围内,是因为它可以进行边界检查。而对于c + <an integer>(其中c为变量),编译器通常无法进行边界检查。


0

这是因为整数或比int小的字面量,如byte、short和char都是int类型。请以以下方式理解:

代码:

  byte a = 10;//compile fine
  byte b= 11;//compile fine
  byte c = a+b;//compiler error[says that result of **a+b** is **int**]

对于任何数学运算,如“除法”、“乘法”和其他算术运算,都会发生同样的情况。因此,将结果转换为所需数据类型的字面量。

byte c = (byte)(a+b);

所以当你执行

   c= c+1;//compiler error

c+1的结果是int类型而不是char类型。因此编译器会为此产生编译时错误。 所以您需要提供一个基本的强制转换来将文字转换为char数据类型。 希望这个例子能提供一些理解。。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接