为什么Java 12会尝试将开关的结果转换为数字?

az31mfrm  于 2023-01-04  发布在  Java
关注(0)|答案(1)|浏览(116)

我同意此代码:

var y = switch (0) {
    case 0 -> '0';
    case 1 -> 0.0F;
    case 2 -> 2L;
    case 3 -> true;
    default -> 4;
};
System.out.println(y);
System.out.println(((Object) y).getClass().getName());

返回以下内容:

0
java.lang.Character

但是如果你删除布尔值:

var y = switch (0) {
    case 0 -> '0';
    case 1 -> 0.0F;
    case 2 -> 2L;
    default -> 4;
};
System.out.println(y);
System.out.println(((Object) y).getClass().getName());

返回以下内容:

48.0
java.lang.Float

我想这个结果是出乎意料的。

hi3rlvi2

hi3rlvi21#

根据switch表达式的JEP 325,switch表达式是一个多边形表达式:
switch表达式是poly表达式;如果目标类型是已知的,则该类型被下推到每个臂中。如果已知,则开关表达式的类型是其目标类型;如果不是,则通过组合每个案例臂的类型来计算独立类型。
因为您没有 target type,所以不会检查表达式是否匹配任何给定类型,这是预期的。
您可以通过将var替换为以下类型来验证这一点:

int y = switch (0) {
    case 0 -> '0';
    case 1 -> 0.0F;
    case 2 -> 2L;
    case 3 -> true;
    default -> 4;
};

在我的shell中,这将失败:

|  Error:
|  incompatible types: bad type in switch expression
|      possible lossy conversion from float to int
|      case 1 -> 0.0F;
|                ^--^
|  Error:
|  incompatible types: bad type in switch expression
|      possible lossy conversion from long to int
|      case 2 -> 2L;
|                ^^
|  Error:
|  incompatible types: bad type in switch expression
|      boolean cannot be converted to int
|      case 3 -> true;
|                ^--^

但是如果你删除布尔值:...
看一下独立类型是如何确定的就足够了(这里是规则):

独立开关表达式的类型确定如下

  • 如果结果表达式都具有相同的类型(可能是空类型),那么这就是switch表达式的类型。
  • 否则,如果每个结果表达式的类型是boolean或Boolean,则对每个Boolean类型的结果表达式应用拆箱转换(5.1.8),并且开关表达式具有boolean类型。
  • 否则,如果每个结果表达式的类型可转换为数值类型(5.1.8),则切换表达式的类型是应用于结果表达式的数值提升(5.6)的结果。
  • 否则,对具有基元类型的每个结果表达式应用装箱转换(5.1.7),之后,切换表达式的类型是对结果表达式的类型的最小上界(4.10.4)应用捕获转换(5.1.10)的结果。

据我所知,当你删除布尔表达式时,你只剩下数值表达式(char'0'int 48)被提升为float48.0)。
至于为什么float是结果的类型,请参见数值上下文部分。

相关问题