if、while、for等 有加{}与没{}问题
http://topic.csdn.net/u/20110529/07/a617db5b-7c59-4b87-bfe6-a92388cc9b48.html?7510
这是在看了这个帖子里面火龙果前辈[img=http://hi.csdn.net/space-8652126-do-album-picid-823269-goto-down.html][/img],引发的猜想
自己动手做几个试验,果真出问题了:
[img=http://hi.csdn.net/space-8652126-do-album-picid-823270-goto-down.html][/img]
猜想:
for循环在没有加{}是不能识别变量的
只有加{}才能识别变量!
求解!!!
[最优解释]
如果了解变量的作用域和生命周期这个就容易理解了
首先如果在{}定义变量,那么变量的生命周期就会在{}中,当{}结束,变量的生命就结束
那么
for(int i = 0; i <= 10; i++) // 报错举个简单的例子
Integer k = new Integer(i); //这样会导致k被重复定义,
//因为这样k的生命周期没有for的{}限制,
//被当作是整个程序的作用域处理
for(int i = 0; i <= 10; i++) { // 正常
Integer k = new Integer(i); //因为k离开了for的{}生命就结束,
//所以再次进入for的{}可以重新定义,因为是新的一个k
}
class Test {
public void main(String[] args) {
int i = 0;
int i = 1; //会导致重复定义,编译失败
//而这样的定义就不会
{int i = 0;}
{int i = 1;}
}
}[其他解释]
坐等高人释疑!
[其他解释]
没有大括号表示肯定只有一条语句,Java语言规范不允许一个变量声明语句作为一条语句在for、while或do循环中重复执行
这个在《java解惑》一书中也有提到
[其他解释]
沙发一下,图片没插好,就用源码吧:
package CSDN;
public class TestCodeFormat {
public static void main(String[] args) {
for(int i = 0; i <= 10; i++) // 报错
Integer k = new Integer(i);
for(int i = 0; i <= 10; i++) { // 正常
Integer k = new Integer(i);
}
if (true) { // 正常
int temp = 10;
}
if (true) // 报错
int result = 10;
while (true) // 报错
int temp = 10;
while (true) { // 正常
int temp = 10;
}
System.out.println("hi, everybody!");
}
}
[其他解释]
加{}表示可以管住{}里面的所有代码, 如没有叫,只能管住它最靠近的那行代码。
[其他解释]
http://hi.csdn.net/attachment/201105/29/8652126_1306681082hZkh.jpg
[其他解释]
for (int i = 0; i < 10; i++)
System.out.println("hi, everybody!");
for (int i = 0; i < 10; i++) {
System.out.println("hi, everybody!");
}
这两句 效果一样 又作如何解释
[其他解释]
确实,mark,等火龙果前辈现身讲解~
[其他解释]
膜拜,忘了还有{}作用域
[其他解释]
但是如果for(int i=0;i<1;i++) ....呢,这个跟重定义有关系么
[其他解释]
学习了。。
[其他解释]
Integer k = new Integer(i);其实是两句语句的合并:Integer k;和k = new Integer(i);所以jia{}和不加{}不一样。
但是 System.out.println("hi, everybody!");只是一条语句~
[其他解释]
学习了,谢谢哈!!!
[其他解释]
所以说你不是在没有{}for中定义变量就没问题,比如
for (int i=0;i<1;i++) System.out.println(i); //没问题,因为没有定义变量
Integer k;
for (int i=0; i<10; i++) k = new Integer(i); //没问题,因为k是在for前定义的,不会造成重复定义
[其他解释]
还有这种
if (true) // 报错
int result = 10;
这个应该也跟重定义无关吧
[其他解释]
11L也说了,int result = 10相当于两条语句,即int result; result = 10,所以相当于
if (true) {int result;}
result = 0; //导致这个地方找不到定义
[其他解释]
非常感谢 阿宝前辈 的解答 !!!!
[其他解释]
求解,难道循环下面的那条语句不在循环中?
[其他解释]
阿宝 哥你忒给力了 膜拜
[其他解释]
貌似 这位 仁兄是正解、
[其他解释]
你的意思就是说,变量k 还括号外面还可以用?
[其他解释]
这个同学还是挺认真的,其实语法分析是在预编译期完成的,我上面的分析是属于运行期的问题,也就是说,即使语法分析能通过,到了运行期可能还是会产生问题。一般对于编译器来说,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;找不到定义,提示是个不完整的表达式。
严格来说,这些错误也只有在真正编译为二进制声称指令才知道的,但是在预编译的语法检测时就给出了错误信息,所以说,这些都是编译器事先定义好的一些语法规则,编译器是按照这个语法规则去检查语法的合法性的。至于为什么会定义这样的语法规则,于是就有了我们对编译器和运行期可能会带来问题的分析。
[其他解释]
据阿宝前辈的解释,for循环下面要是没有{},刚表示 下面定义的变量的生命周期 不受for循环控制 即当循环到第二次 就会出现重复定义变量的现象,要是有{}则变量的生命周期 仅局限于{} 受for循环的控制,每当for循环一次结束时,变量也就被释放了,再进行下一次循环,就重新定义变量,覆盖原本的值,不会出现重新定义及编译异常。我是这样理解的!
[其他解释]
学习了!
[其他解释]
其实不用太纠结于这些东西,这些在编译器的语法检查规则里早就定义好的。我们的分析,只是为了知道如果没有这样的语法规则会带来什么样的问题,知道这些就可以了。
[其他解释]
那就加上{}不就完了嘛
[其他解释]
该回复于2011-05-30 09:47:31被版主删除
[其他解释]
加括号只是为了控制作用范围而已吧
[其他解释]
路过学习。
[其他解释]
学习 顶楼上
[其他解释]
学习来了
[其他解释]
交流也是个学习的过程,呵呵,谢谢哈!!!
[其他解释]
学习学习
[其他解释]
谜题55:特创论
某些时候,对于一个类来说,跟踪其创建出来的实例个数会非常用有,其典型实现是通过让它的构造器递增一个私有静态域来完成的。在下面的程序中,Creature类展示了这种技巧,而Creator类对其进行了操练,将打印出已经创建的Creature实例的数量。那么,这个程序会打印出什么呢?
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;
}
}
这是一个捉弄人的问题。该程序看起来似乎应该打印100,但是它没有打印任何东西,因为它根本就不能编译。如果你尝试着去编译它,你就会发现编译器的诊断信息基本没什么用处。下面就是javac打印的东西:
Creator.java:4: not a statement
Creature creature = new Creature();
^
Creator.java:4: ';' expected
Creature creature = new Creature();
^
一个本地变量声明看起来像是一条语句,但是从技术上说,它不是;它应该是一个本地变量声明语句(local variable declaration statement)[JLS 14.4]。Java语言规范不允许一个本地变量声明语句作为一条语句在for、while或do循环中重复执行[JLS 14.12-14]。一个本地变量声明作为一条语句只能直接出现在一个语句块中。(一个语句块是由一对花括号以及包含在这对花括展中的语句和声明构成的。)
有两种方式可以订正这个问题。最显而易见的方式是将这个声明至于一个语句块中:
for (int i = 0; i < 100; i++) {
Creature creature = new Creature();
}
然而,请注意,该程序没有使用本地变量creature。因此,将该声明用一个无任何修饰的构造器调用来替代将更具实际意义,这样可以强调对新创建对象的引用正在被丢弃:
for (int i = 0; i < 100; i++)
new Creature();
无论我们做出了上面的哪种修改,该程序都将打印出我们所期望的100。
请注意,用于跟踪Creature实例个数的变量(numCreated)是long类型而不是int类型的。我们很容易想象到,一个程序创建出的某个类的实例可能会多余int数值的最大值,但是它不会多于long数值的最大值。
int数值的最大值是231-1,即大约2.1×109,而long数值的最大值是263-1,即大约9.2×1018。当前,每秒钟创建108个对象是可能的,这意味着一个程序在long类型的对象计数器溢出之前,不得不运行大约三千年。即使是面对硬件速度的提升,long类型的对象计数器也应该足以应付可预见的未来。
还要注意的是,本谜题中的创建计数策略并不是线程安全的。如果多个线程可以并行地创建对象,那么递增计数器的代码和读取计数器的代码都应该被同步:
// Thread-safe creation counter
class Creature {
private static long numCreated;
public Creature() {
synchronized (Creature.class) {
numCreated++;
}
}
public static synchronized long numCreated() {
return numCreated;
}
}
或者,如果你使用的是5.0或更新的版本,你可以使用一个AtomicLong实例,它在面临并发时可以绕过对同步的需求。
// Thread-safe creation counter using AtomicLong;
import java.util.concurrent.atomic.AtomicLong;
class Creature {
private static AtomicLong numCreated = new AtomicLong();
public Creature() {
numCreated.incrementAndGet();
}
public static long numCreated() {
return numCreated.get();
}
}
请注意,把numCreated声明为瞬时的是不足以解决问题的,因为volatile修饰符可以保证其他线程将看到最近赋予该域的值,但是它不能进行原子性的递增操作。
总之,一个本地变量声明不能被用作for、while或do循环中的重复执行语句,它作为一条语句只能出现在一个语句块中。另外,在使用一个变量来对实例的创建进行计数时,要使用long类型而不是int类型的变量,以防止溢出。最后,如果你打算在多线程中创建实例,要么将对实例计数器的访问进行同步,要么使用一个AtomicLong类型的计数器。
[其他解释]
加{}表示可以管住{}里面的所有代码, 如没有,只能管住它最靠近的下一行代码,前提是最靠近的那行代码只有一个操作
如:
,只有一个赋值操作。
Integer k ;
for(int i = 0;i<10;i++)
k = new Integer(i);
而
有了两个操作,一个是声明,一个事赋值。
for(int i = 0;i<10;i++)
Integer k = new Integer(i);
楼主可以试一试。
[其他解释]
7楼 阿宝 给力。
[其他解释]
使用{}
是因为里面有多行代码
不是用{}
默认只会执行第一行代码。
[其他解释]
该回复于2011-06-01 17:25:37被版主删除
[其他解释]
扯淡
[其他解释]
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; //导致这个地方找不到定义
[其他解释]
my god,你的代码能退出来吗?
有{},则if,while等的执行体是{}内的所有内容,如果没有{},则执行if/while后的第一条内容。例如:
int a = 10;
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;}
当然相当于不等于完全等价,只是从执行结果上看,效果差不多,所以可以把问题细分