Java:不能在交换机中处理一个案例

我编了一个游戏。 我用开关盒来实现状态机。 问题是,如果ZIEHEN_SP break语句不起作用。 当我调试它时,编译器只是跨越break语句并转到下一个案例ZIEHEN_BA。

我评论了编译器忽略break语句的部分。

为什么?

import java.util.*;
import java.util.Scanner; 
import java.io.*;

class BlackJack2 {

    static int chips = 100;
    static int einsatz = 0;

    enum State { INIT, EINSATZ,ZIEHEN_SP, ZIEHEN_BA}
    static State state = State.INIT;

    static ArrayList<Integer> bankKarten = new ArrayList<Integer>();
    static ArrayList<Integer> spielerKarten = new ArrayList<Integer>();

    static Scanner scanner = new Scanner(System.in); 
    static String s = "";
    static int eingabe = 0;

    static void init(){
        System.out.println("nEin neues Spiel beginnt: ");
        bankKarten.clear();
        spielerKarten.clear();
        bankKarten.add(giveCard());
        spielerKarten.add(giveCard());
    }

    static void chipsSetzen(){
        einsatz = 0;
        if(chips == 0){
            System.out.print("nSie haben " + chips + " Chips!");
            System.exit(1);
        }

        do{
            System.out.print("nSie haben " + chips + " Chips");
            System.out.print("nWie viel moechten Sie setzen? ");
            try{
                einsatz = Integer.parseInt(scanner.next());
            } catch(Exception e){

            }
        } while(einsatz <= 0 || einsatz > chips);

        chips -= einsatz;
    }

    static int sumSpielerKarten(){
        int sum=0;
        for(int i=0; i<spielerKarten.size(); i++){
            sum +=spielerKarten.get(i);
        }
        return sum;
    }

    static int sumBankKarten(){
        int sum=0;
        for(int i=0; i<bankKarten.size(); i++){
            sum +=bankKarten.get(i);
        }
        return sum;
    }

    static int giveCard(){
        return (int)(Math.random()*11+1);
    }

    static boolean oneMoreCard(){
        int ss = sumSpielerKarten();

        if(ss >= 21){
            return false;
        } else {
            do{
                System.out.print("nMoechten sie eine witere Karte ziehen? (y/n): ");
                s = scanner.next();
                if(s.equals("y")){
                    return true;
                } else if(s.equals("n")){
                    return false;
                }
            } while(!s.equals("y") || !s.equals("n"));
        }
        return false;
    }

    static String evaluateWinner(int s, int b){
        String ret = "";
        if(b > 21 || (s > b && s<=21) || s == 21 && b != 21){ 
            ret = "Player";
        } else if(s > 21 || b > s || b == 21 && s != 21){
            ret = "Bank";
        } else if(b == s){
            ret = "Both";
        }
        return ret;
    }

    static int updateMoney(int s, int b){
        String winner = evaluateWinner(s, b);
        int newChips = 0;

        if(winner == "Player"){
            newChips =  einsatz*2 + chips;
        } else if(winner == "Both"){
            newChips =  einsatz + chips;
        } else if(winner == "Bank"){
            newChips = chips;
        }

        System.out.println("Winner: "+ winner);
        return newChips;
    }

    static void showCards(){
        System.out.print("nBank:t");
        for(int i=0; i<bankKarten.size(); i++){
            System.out.print( "[" + bankKarten.get(i) + "]");
        }
        System.out.println("t= " + sumBankKarten());

        System.out.print("Player:t");
        for(int i=0; i<spielerKarten.size(); i++){
            System.out.print( "[" + spielerKarten.get(i) + "]");
        }
        System.out.println("t= " + sumSpielerKarten());
    }

    static void banksTurn(){
        int sb = sumBankKarten();
        int ss = sumSpielerKarten();
        if(sb != 21 && ss != 21 && ss < 21){
            while(sb < 17 ||  (ss > sb && sb < 17)){
                bankKarten.add(giveCard());
            }
        }
        updateMoney(ss, sb);
    }

    public static void main(String args[]){
        while(true){
            switch(state){
                case INIT:
                    init();
                    state = State.EINSATZ;
                    break;
                case EINSATZ:
                    chipsSetzen();
                    state = State.ZIEHEN_SP;
                    break;
                case ZIEHEN_SP:
                    showCards();
                    while(oneMoreCard()){
                        spielerKarten.add(giveCard());
                        showCards();
                    }
                    state = State.ZIEHEN_BA;
                    break; // << Compiler ignores this statement and goes directly to case ZIEHEN_BA
                case ZIEHEN_BA:
                    banksTurn();
                    state = State.INIT;
                    break;
            }
        }
    }

}

因为您将state更改为与State.ZIEHEN_BA条件匹配的值:

 state = State.ZIEHEN_BA;

所以在这里 :

while(true){
   ... 
       state = State.ZIEHEN_BA;
       break; 

    case ZIEHEN_BA:
       banksTurn();
       state = State.INIT;
       break;
   ...
}

在循环的下一次迭代中执行case ZIEHEN_BAcase ZIEHEN_BA

Eclipse展示的可能是对运行时或编译器执行的JVM的优化。 你可以拆开班级以获得更多信息。


编辑

我已经完成了测试,我不认为这是一个编译器优化。

看看这个最小的例子,我没有在案例中设置状态:

public class TestSwitch {

    public enum MyEnum {
        A, B
    };

    public static void main(String[] args) {

        MyEnum state = MyEnum.A;

        while (true) {
            switch (state) {

            case A:             
                break;

            case B:
                break;
            }
        }
    }
}

这里是main()方法的反汇编代码:

 public static void main(java.lang.String[]);
   Code:
      0: getstatic     #18                 // Field a/TestSwitch$MyEnum.A:La/TestSwitch$MyEnum;
      3: astore_1
      4: invokestatic  #24                 // Method $SWITCH_TABLE$a$TestSwitch$MyEnum:()[I
      7: aload_1
      8: invokevirtual #27                 // Method a/TestSwitch$MyEnum.ordinal:()I
     11: iaload
     12: tableswitch   { // 1 to 2
                    1: 36
                    2: 39
              default: 39
         }
     36: goto          4
     39: goto          4

并查看情况A中设置状态的版本,以便在情况B中输入:

public class TestSwitch {

    public enum MyEnum {
        A, B
    };

    public static void main(String[] args) {

        MyEnum state = MyEnum.A;

        while (true) {
            switch (state) {

            case A:
                state = MyEnum.B;
                break;

            case B:
                break;
            }
        }
    }
}

这里是main()方法的反汇编代码:

 public static void main(java.lang.String[]);
   Code:
      0: getstatic     #18                 // Field a/TestSwitch$MyEnum.A:La/TestSwitch$MyEnum;
      3: astore_1
      4: invokestatic  #24                 // Method $SWITCH_TABLE$a$TestSwitch$MyEnum:()[I
      7: aload_1
      8: invokevirtual #27                 // Method a/TestSwitch$MyEnum.ordinal:()I
     11: iaload
     12: tableswitch   { // 1 to 2
                    1: 36
                    2: 43
              default: 43
         }
     36: getstatic     #31                 // Field a/TestSwitch$MyEnum.B:La/TestSwitch$MyEnum;
     39: astore_1
     40: goto          4
     43: goto          4

这个编译代码没有优化。

案例A执行后:

     36: getstatic     #31                 // Field a/TestSwitch$MyEnum.B:La/TestSwitch$MyEnum;
     39: astore_1

下一条指令是转到循环:

40: goto          4

所以优化可能由JVM或Eclipse调试器在运行时执行。


编译器优化了你的代码:-)

当您将开关变量设置为State.ZIEHEN_BA ,它们之间没有什么要执行( while (true)并重新进入开关),这正是要执行的下一行。

我不确定它是否应该这样做(更改开关内部的变量会导致下面的情况被检查),但在你的情况下,我完全同意编译器。

正如你在这个例子中看到的那样,这种行为并非总是如此:

public static void main(String[] args) {
    int i = 3;
    switch(i) {
    case 1:
        System.out.println("1:");
        break;
    case 2:
        System.out.println("2:");
        break;
    case 3:
        System.out.println("3:");
        i = 5;
        break;
    case 4:
        System.out.println("4:");
        break;
    case 5:
        System.out.println("5:");
        i = 5;
        break;
    case 6:
        System.out.println("6:");
        break;
    case 7:
        System.out.println("7:");
        break;
        default:
            break;
    }
    System.out.println("I = " + i);
}

结果是

 3:
 I = 5

这是一个优化。 当你将状态设置为ZIEHEN_BA时,编译器知道它会作为下一步到达那里。 没有优化,只会有一些辅助步骤,但无论如何它都会到达那里:

设置状态; 休息一下; 到了那个时候(真的),现在做开关,然后......到达ZIEHEN_BA。 所以这相当于直接去那里。

链接地址: http://www.djcxy.com/p/84439.html

上一篇: Java: Cant break after a case in a switch

下一篇: Objective C global constants with case/switch