这个同学还是挺认真的,其实语法分析是在预编译期完成的,我上面的分析是属于运行期的问题,也就是说,即使语法分析能通过,到了运行期可能还是会产生问题。一般对于编译器来说,int result = 0;会被解析为2条语句,即int result;和result = 0;然而,int result只是个定义,并不是一个指令,也就是说在编译为二进制时,int result只是会在栈的数据区为变量分配一个地址,我们都知道if,for,while如果没有{},解析的时候只有最近的一个指令有效,于是,编译器会发现,紧接着if,for,while的只是个定义不是指令,会给出错误信息xxx不是一条语句(也就是说不是一个命令)。同时,语法分析是对整个程序的一个扫描,也就是说并不是找到了错误就停止,还会继续解析后面的代码,找出错误,直到扫描结束,给出所有的错误信息。所以可以简单的测试, if (true) int result; if (true) int result = 0; 后面的一条语句会多报一个错误,因为后一条语句相当于if (true) {int result;} result = 0; 会导致result = 0;找不到定义,提示是个不完整的表达式。 严格来说,这些错误也只有在真正编译为二进制声称指令才知道的,但是在预编译的语法检测时就给出了错误信息,所以说,这些都是编译器事先定义好的一些语法规则,编译器是按照这个语法规则去检查语法的合法性的。至于为什么会定义这样的语法规则,于是就有了我们对编译器和运行期可能会带来问题的分析。
public class Creator { public static void main(String[] args) { for (int i = 0; i < 100; i++) Creature creature = new Creature(); System.out.println(Creature.numCreated()); } }
class Creature { private static long numCreated = 0; public Creature() { numCreated++; } public static long numCreated() { return numCreated; } }
for(int i = 0;i<10;i++){ Integer k = new Integer(i); }
实际上就是循环创建十个k对象,如果没有{}的话,会存在重复定义的操作 [其他解释]
其实这个问题很简单,就像在JAVA中不能定义 int k = 0L 一样; 仅仅是个语法问题,除非你要研究1+1为什么等于2。 [其他解释]
学习咯,多谢前辈的解答哈!!! [其他解释]
这个说错了吗? [其他解释]
谢谢前辈的解释! [其他解释] studying`````` [其他解释]
看来这得深入了解,并非那么简单,呵呵 [其他解释]
可以尝试去编译 if (ture) int result; 和 if (true) int result = 0; 可以看看两种在编译上的错误信息有什么不同?除了你说的Java语言规范不允许一个本地变量声明语句作为一条语句在for、while或do循环中重复执行[JLS 14.12-14]错误信息外,还会有个表达式检查的错误信息。 其实就像43L说的,这些都是语法规定,我们在这里所作的讨论,也只是在讨论这个语法规定存在的必要性,没有它可能会带来什么影响。 [其他解释] 如果条件语句里面只有一句语句要执行,那么就可以不能{},如果有两句或是以上,那就要用到{}了 [其他解释]
其实语言都有语法规则,按规范写程序,基本就不会发生问题,所以也没什么好深入的。 比如 int i=0, j=1; int k = ++i+++j; //像这种不规范的代码,也一样被语法检查卡住,因为这样会造成解析歧义 ++i+++j可以被理解 (++i)+(++j)或((++i)++)+j; 好,来看int k = (++i)+(++j);编译正常,因为没有解析歧义 再看 int k = ((++i)++)+j; 编译失败,看上去好像符合逻辑,为何编译不了,再来分析一下(++i)是个表达式,计算时会有个临时表达式值被保存,再看((++i)++),可知,这样会造成临时表达式值++,这显然和本来的意图不一致的,而且表达式的值是计算过程中被临时压栈出栈的,并没有在数据区为其分配内存,所以++操作上出现了问题(没法操作相应的内存地址,因为它没有被分配内存)。这些分析其实都是从运行期的角度来考虑的,然而语法检查的时候就被检查出来了,说明语法检查时定义好了这样的规则,不允许这样的表达式通过。 所以如果真想深入了解,那就要去了解java语法分析器的具体实现,看看其单词如何的出栈入栈,出栈入栈的时候都采用什么样的规则来检查。这些如果不是java的研究专家,只是为了做项目,估计有点小题大做。一般来说,只要假设其语法能通过,那么将会导致什么问题,来大概分析一下就差不多了。
[其他解释] 说扯淡指的是这些:
11L也说了,int result = 10相当于两条语句,即int result; result = 10,所以相当于 if (true) {int result;} result = 0; //导致这个地方找不到定义
不是说这个语句能编译
11L也说了,int result = 10相当于两条语句,即int result; result = 10,所以相当于 if (true) {int result;} result = 0; //导致这个地方找不到定义
while(a<1000){//有了{},则执行两条 int b = 5; a = a* b; } 没有{}的例子 while(a<1000) a= a * a;//没有{},只能执行这条
int b=1000; .... [其他解释] 学习,好 [其他解释]
这个只是说相当于,是为了分析问题。 至于你说的 按照上面那个理论,就变成 public class Test { private int result; result = 10; }
然而,此处是不允许进行单独赋值的
这里其实相当于 public class Test { private int result; {result = 10;} //因为语句要么在方法里,要么在{}里 }
[其他解释] xue学习了 [其他解释] 具体为什么不能这样,我不得而知,但“int result = 10相当于两条语句,即int result; result = 10,所以。。。”这个结论绝对是行不通的
如 public class Test { private int result = 10; }
按照上面那个理论,就变成 public class Test { private int result; result = 10; }
然而,此处是不允许进行单独赋值的
[其他解释]
那我想详细听听你对 if (true) int result = 0;的编译出错的解释 除了认可的Java语言规范不允许一个本地变量声明语句作为一条语句在for、while或do循环中重复执行[JLS 14.12-14]错误信息外,还会有个表达式检查的错误信息。 也就是说比单纯的 if (true) int result;编译出的错多。 我想知道这个表达式错误信息指的是那个表达式?怎么错的? 或许你对java的语法分析器有一定的了解,愿闻其详。 [其他解释]
其实定义不算语句,定义在编译的时候只是在内存段为变量分配空间,也就是给变量一个分配一个相对地址,后面的操作都是针对这个地址而操作。 class Test { private int a = 10; }
class Test { private int a; {a = 10;} } 可以比较两个的反编译代码,除了LineNumberTable:的一个地方不同,其他的完全相同,所以可以说
private int a = 10; 相当于 private int a; {a = 10;} 当然相当于不等于完全等价,只是从执行结果上看,效果差不多,所以可以把问题细分
其实定义不算语句,定义在编译的时候只是在内存段为变量分配空间,也就是给变量一个分配一个相对地址,后面的操作都是针对这个地址而操作。 class Test { private int a = 10; }
class Test { private int a; {a = 10;} } 可以比较两个的反编译代码,除了LineNumberTable:的一个地方不同,其他的完全相同,所以可以说 private int a = 10; 相当于 private int a; {a = 10;} 当然相当于不等于完全等价,只是从执行结果上看,效果差不多,所以可以把问题细分