【问题标题】:Casting characters in JavaJava中的字符转换
【发布时间】:2012-12-06 18:00:49
【问题描述】:

我正在学习 Java。我发现表达式通常必须转换为某种类型才能正确执行。例如,在算术评估期间,字节被提升为整数,因此以下表达式将抛出错误:

byte b = 10;
int i;
i = b*b;  //ok, assigning an integer evaluation to an integer variable
b = b*b;  // throws error, coz assigning integer evaluation to byte variable

现在,我知道将整数分配给字符变量是可以的:char a; a = 88; 可以。但是,如果我这样做:

char c2 = 'b', c3 = 'c';
c2 = c2 + c3; //throws error
c2 = (char)(c2 + c3); //works fine

为什么不强制转换时会抛出错误?毕竟右手边还是一个整数,所以给一个字符变量赋值一个整数应该就可以了。

【问题讨论】:

  • 88 是一个字节,而不仅仅是一个整数

标签: java


【解决方案1】:

java中每种基本类型可以容纳多少值是有一定限制的。分配算术运算的结果会在运行时产生不可预知的结果,JVM不确定char是否可以容纳,因此编译错误。

【讨论】:

    【解决方案2】:

    c2 + c3 中,两个操作数都隐式扩展为int,因此相加的结果也是int

    JLS §15.18.2. Additive Operators (+ and -) for Numeric Types:

    对操作数执行二进制数字提升(第 5.6.2 节)。

    JLS §5.6.2. Binary Numeric Promotion:

    当运算符对一对操作数应用二进制数值提升时,每个操作数都必须表示一个可转换为数值类型的值,以下规则按顺序适用:

    加宽原语转换(第 5.1.2 节)适用于转换以下规则中指定的一个或两个操作数:

    • 如果任一操作数是 double 类型,则另一个将转换为 double。

    • 否则,如果任一操作数为浮点类型,则将另一个转换为浮点类型。

    • 否则,如果其中一个操作数是 long 类型,则将另一个转换为 long。

    • 否则,两个操作数都转换为 int 类型。

    因此,您最终会得到一个int。将其分配给 char 变量需要显式转换。

    你说:

    由于整数值可以分配给字符变量...

    只有 constant 整数表达式可以分配给 char 变量而不需要强制转换。

    JLS §5.2. Assignment Conversion:

    此外,如果表达式是 byte、short、char 或 int 类型的常量表达式(第 15.28 节):

    • 如果变量的类型是 byte、short 或 char,并且常量表达式的值可以用变量的类型表示,则可以使用缩小原语转换。

    此自动缩小转换不适用于此处。你需要一个明确的演员表。

    【讨论】:

    • 是的,这就是我所说的。右边的字符被提升为整数,从而将整数结果分配给左边的变量。既然整数值可以赋值给字符变量,为什么会报错呢?
    • +1 表示常量 - 我找不到参考 ;-)
    • @Cupidvogel:这不太正确。只有 constant 整数表达式会自动变窄,这里我们不看。我已经扩展了答案。
    • 常量表达式到底是什么意思?
    • @Cupidvogel 如在15.28 中定义的描述中所详述。基本上:文字、final 变量或文字和最终变量的组合。
    【解决方案3】:

    一个进一步说明的例子:

    char c1 = Character.MAX_VALUE;
    char c2 = Character.MAX_VALUE;
    char c3 = (char) (c1 + c2);
    int  i3 = c1 + c2;
    
    System.out.printf("After casting to char: %s, the int value: %s%n", (int) c3, i3);
    

    所以我们实际上得到了一个错误的数学结果。

    【讨论】:

      【解决方案4】:

      看看线程:

      Integer arithmetic in Java with char and integer literal

      原因似乎是“c2 = c2 + c3;”编译器无法检查(它在运行时执行)而“char a; a = 88;”由编译器直接完成。

      【讨论】:

      • 为什么会这样?作业之间有什么区别?
      • 它的工作原理是这样的:如果编译器可以即时将数值转换为 byte 或 char,它就会这样做。如果赋值是在运行时执行的,它会遵循其他的转换路径。把它当作一个方便的编译器实用程序或作为语言的不连贯性(无论你最喜欢哪个;-)
      【解决方案5】:

      char 是 2 个字节,int 是 4 个字节。当你写 char c = 1;这并不意味着 1 是 int,它只是 javac 的一个常量,javac 知道 1 适合 char。但是 c2 = c2 + c3;是算术运算,javac 会将其解释为(int)c2 + (int)c3,这会产生 int 结果。 int 不适合 char,因此 javac 会警告您可能会丢失精度。

      【讨论】:

      • char 是 2 个字节,int 是 4 个字节。当你写 char c = 1;这并不意味着 1 是 int,它只是 javac 的一个常量,javac 知道 1 适合 char。 当 1 占 4 个字节而 char 占 2 个字节时,1 怎么能适合 char
      • 其实1只占1个字节,就是0x1,编译器知道合适。但是如果你有 int i = 1;字符 c = i;它不会编译,因为 i 是一个 var 它可以长于 2 个字节
      • 所以你的意思是,即使整数具有默认的空间占用,整数文字不遵守这一点并占用空间临时?
      • 我的意思是char = 1中的1只是一个整数常量,int是局部变量、参数和字段的类型。
      • 你说1占用1个字节,而int i; i = 1;中,i占用4个字节。这是为什么呢?
      【解决方案6】:
      char c2 = 'b', c3 = 'c';
      c2 = c2 + c3; //throws error
      c2 = (char)(c2 + c3); //works fine
      

      当你在做c2+ c3

      添加这些字符的 ASCII 值,返回 int 结果。 当您将int 结果分配给char 时,它会给出错误。

      【讨论】:

      • 这就是我所说的,如果我这样做char c = 99; 它不会抛出错误,那么为什么在这里呢?
      • 字符 c = 99; 99 被隐式转换为 char。因为在编译时 99 的数据类型是已知的,但在编译时不知道字符算术返回类型结果。
      【解决方案7】:

      将 int 88 分配给 char 有效,因为编译器可以确定值。

      编译器无法处理 c2 = c2 + c3 的情况。值 c2 + c3 必须在运行时计算。因此,编译器无法确定必须分配的实际 char 值。

      【讨论】:

        【解决方案8】:

        将 int 分配给 char 不一定能正常工作。字符只有 16 位,整数是 32 位,所以可能会溢出。

        一般来说,如果赋值不会导致溢出,Java 只允许在没有强制转换的情况下赋值原始值。

        【讨论】:

        • 这里为什么会溢出?
        • 简单:取两个可能的最高 char 值并将它们相加。那是溢出。 ('\uFFFF' + '\uFFFF') > Character.MAX_VALUE
        • 这有点捷径可走。 int i = 1; char c = i; 不会编译,虽然没有溢出。
        • 嗯,因为它不是一个常量赋值,如下面的 NPE 解释的那样?
        • @Cupidvogel 是的。例如final int i = 1; char c = i; 会编译,因为i 现在是一个常量。
        猜你喜欢
        • 2013-07-28
        • 1970-01-01
        • 1970-01-01
        • 2013-01-29
        • 1970-01-01
        • 2010-12-28
        • 1970-01-01
        • 1970-01-01
        • 2011-03-25
        相关资源
        最近更新 更多