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_BA
的case 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