【问题标题】:Why is my char printing as a number instead of a character?为什么我的字符打印为数字而不是字符?
【发布时间】:2015-08-26 03:03:22
【问题描述】:

根据 Java 三元运算符expression ? statement1 : statement2, 如果expression 为真则statement1 将被执行,如果expression 为假则statement2 将被执行。

但是当我跑步时:

// some unnecessary codes not displaying
char y = 'y';
int i = 0;
System.out.print(false ? i : y);

我希望它打印y,但它打印121,为什么?

编辑 根据 manouti 的回答,编译器解释为 int,但如果是这种情况,那么为什么我在 i 看到死代码?

如果我执行System.out.print(false ? 0 : x);,那么我得到y,那么为什么在这种情况下编译器不解释为int?

【问题讨论】:

  • 编译器真的应该拒绝这些情况——人类程序员要理解所有的小细节并不容易。当编译器比程序员聪明时,就会有麻烦。

标签: java char int


【解决方案1】:

121 是字符y 的整数表示。由于您提供了 i 作为表达式的一部分,编译器将其解释为对 System.out.print(int) 的调用,而不是 System.out.print(char)。

请注意,更改为 System.out.print(false ? (char)i : y); 会打印出 y。

【讨论】:

  • 但是为什么?在我的日食中,它在 i 处显示死代码,所以这意味着 i 无法访问,即使那样它为什么解释为 int
  • @rocking 您始终可以将 char 视为 int,但并不总是将 int 视为 char(我认为,不是 Java 专家)。由于表达式的类型必须是常量,我想这就是它被推断为 int 的原因。
  • @rocking 你有死代码,因为你在三元运算符中使用常量boolean 作为条件。 Java 编译器能够推断出,true 的情况从未输入过,因此无法访问。
  • @OMGtechy 因为表达式的类型必须是常量 没必要这么复杂。 Java 中的每个表达式只有一种类型和一种类型。三元运算符也是如此。正在发生的是从char 到int 的(自动)向上转换,因此三元运算符具有正确定义的类型(在本例中为:int)。
  • 隐式转换链:byte -> short -> int -> long
【解决方案2】:

对您的问题的简短回答是,打印的值基于条件表达式计算的类型。

所以你的问题真的归结为,为什么条件表达式的类型不同

char y = 'y';
int i = 0;
System.out.print(false ? i : y); // prints 121

和

char y = 'y';
System.out.print(false ? 0 : y); // prints y

要回答这个问题,我们需要查看section §15.25 of the Java Language Specification。

Java 中的条件表达式分为三种:

  • 布尔条件表达式
  • 数值条件表达式
  • 引用条件表达式

由于int 和char 都可以转换为数值类型,因此根据此规则,该表达式是数值条件表达式的示例:

如果第二个和第三个操作数表达式都是数值表达式,则条件表达式是数值条件表达式。

为了对条件进行分类,以下表达式为数值表达式:

  • 独立形式的表达式(第 15.2 节),其类型可转换为数字类型(第 4.2 节,第 5.1.8 节)。

因此,确定整个表达式的类型的规则如下:

15.25.2。数值条件表达式

数值条件表达式是独立的表达式(第 15.2 节)。

数值条件表达式的类型确定如下:

  • 如果第二个和第三个操作数的类型相同,那么就是条件表达式的类型。

  • 如果第二个和第三个操作数之一是原始类型 T,而另一个的类型是对 T 应用装箱转换(第 5.1.7 节)的结果,则条件表达式的类型为T.

  • 如果其中一个操作数是byte或Byte类型,另一个是short或Short类型,则条件表达式的类型为short。

  • 1234563条件表达式的类型是T。
  • 如果其中一个操作数是 T 类型,其中 T 是 Byte、Short 或 Character,而另一个操作数是 int 类型的常量表达式,其值可在 U 类型中表示,U 是对T进行拆箱转换,则条件表达式的类型为U。

  • 否则,二进制数值提升(第 5.6.2 节)应用于操作数类型,条件表达式的类型是第二个和第三个操作数的提升类型。

请注意,二进制数字提升执行值集转换(第 5.1.13 节)并可能执行拆箱转换(第 5.1.8 节)。

注意第四条规则准确地描述了第二个例子;第二个操作数是int (0) 类型的常量,第三个是char,因此条件表达式的计算结果为char。这将导致编译器使用print(char) 方法,该方法将打印y。

但是,当您改为传入 variable 而不是 constant 时,您会陷入最后一条规则,即“...条件表达式的类型是第二个和第三个操作数的提升类型。"

如果你看一下section §5.6.2 of the JLS,它描述了类型提升的规则如下:

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

  1. 如果任何操作数属于引用类型,则将对其进行拆箱转换(第 5.1.8 节)。

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

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

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

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

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

通过遵循这些规则,表达式的类型将为int,因此编译器将使用print(int) 方法,该方法将打印121(y 的 ascii 值)。

【讨论】:

  • 一直在 JLS +1 中寻找这个
  • @manouti 真正让我吃惊的是它指定常量必须是 int 才能自动评估为另一个操作数的类型,因此 print(false ? 0L : y) 属于二进制数字提升就像使用变量一样,并再次打印121。
  • 我认为这与以下事实有关:在 Java 中,整数文字可以自动分配给更具体的原始变量,例如 short,当它们的值适合时,例如short c = 0; 可以在没有演员表的情况下工作,但 short c = 0L; 不会。
【解决方案3】:

121 是 y 的 ASCII 代码,并且由于您已将 i 声明为整数,因此编译器也将 y 解释为 int 变量。因此打印 y 的 ASCII 值。编写 System.out.print(false ? (char)i : y) 将打印 y。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-11
    • 2016-03-30
    • 2010-09-30
    • 2012-09-12
    • 2015-06-16
    相关资源
    最近更新 更多