【问题标题】:Integer arithmetic in Java with char and integer literalJava中的整数算术与char和整数文字
【发布时间】:2010-09-09 21:13:20
【问题描述】:

有人可以向我解释为什么下面的代码在 Java 中可以编译吗?

char c = 'a' + 10;

为什么这不等价于以下,不编译?

int i = 10;
char c = 'a' + i;

Java 语言规范(第 3.10.1 节)规定“如果整数文字以 ASCII 字母 L 或 l (ell) 为后缀,则其类型为 long;否则为 int 类型(第 4.2 节) .1)。”第 4.2.2 节提到了“数值运算符,它产生intlong 类型的值。”所以在我的理解中,加法的结果应该是一个int,不能赋值给char变量c

但是,它编译得很好(至少在 Sun JDK 1.6.0 第 17 版和 Eclipse Helios 中)。

也许是一个人为的例子,但它被用于我一直在教授的 Java 入门课程中,现在我突然意识到我并不真正理解它为什么会起作用。

【问题讨论】:

  • 感谢所有回答的人。对于任何感兴趣的人,语言规范(赋值转换)的第 5.2 节实际上确实说“此外,如果表达式是 byte、short、char 或 int 类型的常量表达式(第 15.28 节):......缩小原始转换如果变量的类型是 byte、short 或 char,并且常量表达式的值可以在变量的类型中表示,则可以使用。"
  • 如果你和我一样,碰巧偶然发现了这个,因为你想知道如何将索引字符实际转换为字符串,那么你就去吧;当i=2 然后String.valueOf((char)('a'+i)) 返回字符串“c”。

标签: java


【解决方案1】:

这是因为编译器可以检查它 ('a' + 10) 是否在 char 的范围内,而它不能(通常)检查 'a' + <an integer> 是否在范围内。

【讨论】:

  • 字符 c = 65535;编译,但不是 char c = 65536;
  • char 是两个字节,所以这是有道理的。
  • char c = 103000; 没有。 UCS-2 英尺!
【解决方案2】:

'a' + 10 是一个编译时常量表达式,其值为'k',可以初始化char 类型的变量。这与能够用 [-128, 127] 中的文字整数分配 byte 变量相同。在 [128, 255] 范围内的 byte 可能更烦人。

【讨论】:

  • 谢谢。查找编译时常量表达式将我带到了语言规范的相关部分。
  • char c = 'a' + 1L 无法编译,这是有线的
【解决方案3】:

char 实际上是一个无符号的 16 位整数,范围为 0-65535。因此,您可以将该范围内的任何整数文字分配给 char,例如“char c = 96”,这导致“c”包含字符“a”。您可以使用 System.out.println(c) 打印出结果。

对于“char c = 'a' + 10”右侧的常量表达式,由于Java数值提升规则,'a'首先被提升为int,整数值为96。添加后10 到它,我们得到一个文字整数 106,它可以分配给一个 char。

"char c = 'a' + i" 的右边不是常量表达式,表达式结果赋值规则需要从 int 显式转换为 char,即 "char c = (char) ( 'a' + i)"。

【讨论】:

    【解决方案4】:

    常量是不同的类型(我知道规范说 10 应该是一个 int,但编译器不这么认为)。

    char c = 'a' + 10 中,10 实际上被认为是char 类型的常量变量(因此可以添加到a 中)。因此char c = char + char 有效。

    int i = 10; char c = 'a' + i; 中,您将 char 添加到整数(整数可以比 char 大得多,因此它选择更大的数据类型 [int] 作为结果,也就是:'a' + i = int + int)。所以加法的结果是一个整数,不能放入char c

    如果你明确地将i 转换为一个字符(例如:char c = 'a' + (char)i;)它可以工作,或者如果你做了相反的事情(例如:int c = (int)'a' + i;)它会工作。

    【讨论】:

    • 我认为说 10 被认为是 char 类型是不太正确的。相反,正如 Tom Hawtin 所说,表达式'a' + 10 是一个编译时常量,因此允许编译器进行缩小转换。实际上char c = 'a' + (char)i; 不起作用,因为右侧是int 类型并且不是编译时常量。
    【解决方案5】:

    根据 Java 规范,截至 2020 用于扩大和缩小表达式中整数值的转换:

    “在数字算术上下文中 ...提升的类型是int, 并且任何不是int 类型的表达式都会进行加宽 原始转换int"

    分配上下文中

    "...如果表达式是byteshort 类型的常量表达式char,或int

    • 可以使用缩小原语转换 变量的类型为 byteshortchar,并且 常量表达式可以用变量的类型来表示。”

    因此,在char c = 'a' + 10; 中,左侧常量值为char,右侧常量值为int,适合char。虽然有一个assignment 并且int 10 适合char,但int 被转换为char。而加法的整体结果是char

    char c = 'a' + i;(其中int i = 10;)中,i 不是恒定的,因此,尽管进行了赋值,char 'a' 仍被提升为int,整体结果为int。因此,如果没有明确的类型转换,分配是错误的。

    请注意,以下原始答案是错误的(它引用了数字选择上下文中的处理方法,例如switch 语句):

    根据Java规范对表达式中的加宽和收窄转换:

    如果任何表达式的类型为int 并且不是常量表达式, 那么提升的类型是int,以及其他不属于的表达式 类型 int 经历加宽基元转换int

    ...

    如果任何表达式的类型为char,并且所有其他表达式为 'char' 类型或 'int' 类型的 常量表达式 可以在“char”类型中表示的值,然后是提升的类型 是charint 表达式经历窄化原语 转换char

    因此,在char c = 'a' + 10; 中,左侧表达式是char,右侧常量表达式是int,适合char。因此,常量被转换为char。总体结果是char

    而在char c = 'a' + i;(其中int i = 10;)中,正确的表达式不是常量,所以char 'a'被提升为int,整体结果为int

    【讨论】:

      【解决方案6】:

      这段代码应该可以工作:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-04-10
        • 1970-01-01
        • 1970-01-01
        • 2014-12-08
        • 2020-07-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多