在Java交换机中声明和初始化变量
我有一个关于Java交换机的疯狂问题在Java交换机中声明和初始化变量,java,scope,initialization,switch-statement,declaration,Java,Scope,Initialization,Switch Statement,Declaration,我有一个关于Java交换机的疯狂问题 int key = 2; switch (key) { case 1: int value = 1; break; case 2: value = 2; System.out.println(value); break; default: break; } 场景1-当键为2时,它成功地将值打印为2。 场景2-当我要在案例2中注释valu
int key = 2;
switch (key) {
case 1:
int value = 1;
break;
case 2:
value = 2;
System.out.println(value);
break;
default:
break;
}
场景1-当键为2时,它成功地将值打印为2。
场景2-当我要在案例2中注释value=2
时,它尖叫着说局部变量值可能尚未初始化
问题:
场景1:如果执行流没有转到案例1:
(当键=2
时),那么它如何知道值变量的类型为int
?
场景2:如果编译器知道值变量的类型为int
,那么它必须访问int value=1代码>案例1中的表达式:
(声明和初始化)。那么,当我在案例2:
中注释value=2时,为什么会出现这种情况,说局部变量值可能尚未初始化。
声明在编译时处理,不依赖于
代码的执行流程。因为值
是在本地
开关块的范围,它可以从该块中的任何位置使用
声明的要点
变量已声明(作为int),但未初始化(已分配初始值)。想想这句话:
int value = 1;
作为:
int-value
部分在编译时告诉编译器您有一个名为value的变量,它是一个int。value=1
部分初始化它,但这发生在运行时,如果没有输入开关的分支,则根本不会发生。开关语句的作用域基本上是奇怪的。发件人:
块(§14.4)中局部变量声明的范围是声明出现的块的其余部分,从其自身的初始值设定项开始,并包括局部变量声明语句右侧的任何其他声明符
在您的情况下,case2
与case1
位于同一块中,并出现在它之后,即使case1
永远不会执行。。。因此,局部变量在范围内,并且可以写入,尽管您在逻辑上从未“执行”过声明。(虽然初始化是可执行的,但声明并不是真正的“可执行的”。)
如果注释掉值=2代码>赋值,编译器仍然知道您引用的是哪个变量,但您不会经历任何为其赋值的执行路径,这就是为什么您会像读取任何其他未明确赋值的局部变量时一样出现错误
我强烈建议您不要使用在其他情况下声明的局部变量——正如您所看到的,这会导致代码非常混乱。当我在switch语句中引入局部变量时(我很少尝试这样做——理想情况下,情况应该很短),我通常更喜欢引入一个新的范围:
case 1: {
int value = 1;
...
break;
}
case 2: {
int value = 2;
...
break;
}
我相信这更清楚。在JDK-12早期访问构建中集成了。从以下方面可以看出某些变化:
局部变量范围-开关外壳中的局部变量现在可以是外壳本身的局部变量,而不是整个开关块的局部变量。考虑到Day
enum类的一个示例(与Jon在语法上的尝试类似),以进一步解释:
public enum Day {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}
// some another method implementation
Day day = Day.valueOf(scanner.next());
switch (day) {
case MONDAY,TUESDAY -> {
var temp = "mon-tue";
System.out.println(temp);
}
case WEDNESDAY,THURSDAY -> {
var temp = Date.from(Instant.now()); // same variable name 'temp'
System.out.println(temp);
}
default ->{
var temp = 0.04; // different types as well (not mandatory ofcourse)
System.out.println(temp);
}
}
开关表达式-如果目的是给变量赋值,然后使用它,once可以使用开关表达式。e、 g
private static void useSwitchExpression() {
int key = 2;
int value = switch (key) {
case 1 -> 1;
case 2 -> 2;
default -> {break 0;}
};
System.out.println("value = " + value); // prints 'value = 2'
}
这一解释可能会有所帮助
int id=1;
switch(id){
default:
boolean b= false; // all switch scope going down, because there is no scope tag
case 1:
b = false;
case 2:{
//String b= "test"; you can't declare scope here. because it's in the scope @top
b=true; // b is still accessible
}
case 3:{
boolean c= true; // case c scope only
b=true; // case 3 scope is whole switch
}
case 4:{
boolean c= false; // case 4 scope only
}
}
Java规范:
由于标签中断而导致突然完成的情况按照标签语句的一般规则处理(§14.7)
标记语句:
标签状态:
标识符:语句
LabeledStatementNoShortIf:
标识符:StatementNoShortIf
与C和C++不同,java编程语言没有GOTO语句;
标识符语句标签与break(§14.15)或continue一起使用
(§14.16)出现在标记声明中任何地方的声明
已标记语句的标签范围是
所载声明
换句话说,案例1、案例2是switch语句中的标签。break和continue语句可以应用于标签
因为标签共享语句的作用域,所以标签中定义的所有变量都共享switch语句的作用域。为什么这个答案会被上调?它没有回答这个问题,不像保罗或斯基特的回答……它回答了。所以,+1,一分钱,也是我这边的。+1用于解释编译时和运行时中的声明和初始化。+1用于“虽然初始化是可执行的,但声明不是真正的“可执行的”。”。谢谢你的建议。随着JEP-325的集成,和一可以使用相同的名称跨案件,而不是开关块。尽管它也依赖于类似的块编码。此外,在开关表达式中,为每个开关大小写指定一个变量的值将非常方便。使用大括号添加新作用域的要点。我甚至不知道你可以这样做。这不是一个疯狂的问题,这是一个非常好的问题。可能是@PhilippeCarriere的重复事实上,我认为应该是相反的-这里的答案更好(即使帖子更新),因为这里直接引用了JLS,并且很好地总结了该帖子中不同答案所涵盖的问题@Tunaki重复的描述以“这个问题以前被问过”开头。我在读这篇文章,因为后一篇文章应该被标记为前一篇文章的副本。但我同意这一点,它有很好的元素。也许他们应该以某种方式合并?还有很多问题都被标记为与我的原始问题重复,所以如果你决定最好将这一个标记为新的原始问题,请修复所有的链接以引用此问题
int id=1;
switch(id){
default:
boolean b= false; // all switch scope going down, because there is no scope tag
case 1:
b = false;
case 2:{
//String b= "test"; you can't declare scope here. because it's in the scope @top
b=true; // b is still accessible
}
case 3:{
boolean c= true; // case c scope only
b=true; // case 3 scope is whole switch
}
case 4:{
boolean c= false; // case 4 scope only
}
}