打破和开关似乎执行所有的情况语句。

4
在Java和Eclipse(Kempler)的最新稳定版本中,输入以下代码并执行它(假设包名和类名存在):
package some_package;

public class what_the_heck {

    public static void main(String[] args) {
        int p = 2;
        int x = 1;
        switch(p){  
            case (1):
                x--;
            case (2):
                x = 2;
            case (3):
                x = 3;
            default:
                x++;
        }
        System.out.println(x);
    }
}

这会打印出值为4。最初,我认为它应该打印2,因为我认为即使没有break语句,每个代码片段仍然被包含在case语句中。现在我认为问题在于它是如何编译的。例如,我目前的信念是,在内部,一个布尔值跟踪是否有一个case语句等于该值。如果是这样,那么布尔值为真,并且所有case语句将被视为真,直到找到一个break。这是有道理的,但我仍然想知道背后是否还有其他原因,或者我的假设完全错误。


9
“这段代码有意省略了break语句。”“你已经回答了自己的问题。” - rgettman
你为什么不去看一下关于 switch 语句的 Java 文档呢? - Bart
公平地说,switch 的这种从 C 继承而来的 fall through 行为确实有点违反直觉。 - Henry
顺便提一下,根据Java规范,你的类名应该采用驼峰命名法。 - fmsf
@rgettman,我已经编辑了我的问题以更好地适应我的查询。抱歉造成困惑。现在我正在寻找为什么在评估为true的单个case语句之后(当没有break语句时),它们被忽略并执行它们的代码。我的当前想法在问题中。 - user1881400
显示剩余2条评论
4个回答

5

为什么switch工作方式是这样的呢?原因在于:

switch(p){  
        case (1):
            x--;
        case (2):
            x = 2;
        case (3):
            x = 3;
        default:
            x++;
    }

实际上,这只是语法糖(基本上是)的简化版本:

if (p == 1)
    goto .L1;
else if (p == 2)
    goto .L2;
else if (p == 3)
    goto .L3;
else
    goto .L4;

.L1:
    x--;
.L2:
    x = 2;
.L3:
    x = 3;
.L4:
    x++;

Java中没有goto语句,但C有,这就是它的来源。所以如果p是2,它会跳转到.L2并执行该标签后面的所有语句。


3
当你在switch语句中没有使用break时,程序会继续执行其它与入口处在同一层级且位于其下方的case语句。因此,实际上会执行所有这些语句。
 x = 2;
 x = 3;
 x++;
 print(x);
 System.out.println(x);

感谢Pshemo,这里是switch语句规范的链接


但是为什么会这样?在尝试执行之前,它应该仍然将其读作“if p == blah”(否则就没有多大意义了)。我猜这取决于编译方式。 - user1881400
这就像开关的规格说明一样。它是按照设计要求工作的。 - fmsf
4
一如既往,JLS 给出了答案:“如果 case 常量之一等于表达式的值,则我们称该 case 匹配,并且执行 switch 块中匹配 case 标签后的所有语句(如果有的话)。”因此,如果您想停止这种行为,需要在每个 case 的末尾放置 break - Pshemo
1
试着不要把case看作是隔离代码块的一种方式,而是给它一个你可以跳转到的“地址”。你的switch语句说,如果p == 2,那么**跳转到语句x = 2;**并继续执行。它将继续执行每个后续语句,并且不关心这些语句是否有自己的地址(case标签)。如果你想在达到下一个case标签之前停止,你必须明确告诉它使用breakcontinue语句。 - Mike Strobel

1
如果一个case块中的条件为真且没有return或break,所有其他case块都将被执行,无论它们是否为真。
作为一条经验法则,在case块的末尾始终放置一个break或return,这样你就会有90%的正确率。
switch (p) {
    case (1):
        x--;
        break;
    case (2):
        x = 2;
        break;
    case (3):
        x = 3;
        break;
    default:
        x++;
        break;
}

0

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