简单问题的背后:关于if后不加括号的讨论
2008-08-27 22:16
477 查看
看上去一个很简单的问题,结果却不是想象中的那样。良好的编码习惯是多么的重要啊。
原文地址:http://topic.csdn.net/u/20080825/18/34F53E23-ECBC-4A91-B8B5-8C7F2A07F50A.html
测试的代码如下[/b]:
public class TestPrintStream1 {
public static void main(String[] args) {
Class c = TestPrintStream1.class;
try {
Object o = c.newInstance();
if (o instanceof TestPrintStream1)
TestPrintStream1 tt = (TestPrintStream1) o;// 这里为什么会报错呢,说tt 和 TestPrintStream1不能不解析
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
那一行为什么会报错呢?if语句后面不是允许不加大括号吗?
2楼 java2000.net[/b]
if ()
后面不使用花括号时,里面不能出现声明,因为那个涉及到作用域,而没有花括号又没有作用域了。
个人理解。
boolean ok = true;
if(ok)
MyClass c = new MyClass();
这样也是不允许的。
改成
MyClass c = null;
if(ok)
c = new MyClass();
这样是可以的
这个代码问题和 instanceof 没有任何关系
6楼 segazk
Java 把 Test tt = new Test(); 当两条语句看待了相当于 Test tt; tt = new Test();
Eclipse 中报的语法错误是:
Test cannot be resolved
tt cannot be resolved
cmd 下 javac 没通过编译报的错误是:
D:/Test.java:x: 不是语句
Test tt = new Test();
^
D:/Test.java:x: 需要 ';'
Test tt = new Test();
^
2 错误
20楼 bao110908
Java Language Specification 明确指出局部变量声明的作用范围是在一个
块内,也可以理解为在“{ }”内。for 循环可以不使用“{ }”的,但仅限于
执行语句(其中并不包括变量声明语句)
我们看到的代码是这样的:
01 public class TestPrintStream1 {
02
03 public static void main(String[] args) {
04
05 Class c = TestPrintStream1.class;
06 try {
07 Object o = c.newInstance();
08 if (o instanceof TestPrintStream1)
09 TestPrintStream1 tt = (TestPrintStream1) o;
10 } catch (InstantiationException e) {
11 e.printStackTrace();
12 } catch (IllegalAccessException e) {
13 e.printStackTrace();
14 }
15 }
16 }
由于变量作用域的关系,编译器所看到的代码是这样的,注意 09 行的缩进!
01 public class TestPrintStream1 {
02
03 public static void main(String[] args) {
04
05 Class c = TestPrintStream1.class;
06 try {
07 Object o = c.newInstance();
08 if (o instanceof TestPrintStream1)
09 TestPrintStream1 tt = (TestPrintStream1) o;
10 } catch (InstantiationException e) {
11 e.printStackTrace();
12 } catch (IllegalAccessException e) {
13 e.printStackTrace();
14 }
15 }
16 }
从 08 和 09 行编译器所理解的代码中来看,很明显 08 行的 if 语句并没有
结束,因此编译器会认为 if 后面少掉一个语句结束的分号。
笨笨地编译器猜想你的代码应该是这样的,注意 08 行后面的分号
08 if (o instanceof TestPrintStream1);
09 TestPrintStream1 tt = (TestPrintStream1) o;
实际上编译器的这种理解并不是我们想要的。
为了不出现我们所不知的东西来困扰,应该老老实实地在 for, if, while 等语句后面加
上 { },哪怕块中的语句只有一行。
37楼:wargrey
各位,这里有没有熟悉C语言的朋友,相信大家都知道,在C语言里,变量的声明都是要出现在作用域的第一条非赋值语句前的。所以java也是c风格的语言,
它也可能有类似的很细节的规则,就是,java的变量声明必须是一条语句。而java的每个作用域里面的语句分割符是“;”,if (true)
statemenet;只是一条语句,并且如12楼所说,javac提示缺少;,因为它认为声明是一条新语句,而这里却不是。另一个方面javac在解析
到单行if时会假设后面应该是个表达式之类或语句,而声明不是关键字,所以它报出无法解析。
接触过vb的朋友也知道,vb有块if语句和行if语句,虽然java没有明确提到,但是if (true)
statemenet;就是行if语句。行内的作用域与if所在作用域相同。因为作用域是由{}决定的。只是lz提到的问题很难碰到(如果严格参考
java规范的化),所有平时也没人会去考虑。当然我无法证明这个作用域究竟是什么!
这是我的理解。
70楼:ZjJ_Sir
try {
Object o = c.newInstance();
if (o instanceof TestPrintStream1)
{
TestPrintStream1 tt = (TestPrintStream1) o;
}
}这样很明确,tt的作用域在if(){}的{}内({}是块作用域的标志)所以程序没有问题,而:
try {
Object o = c.newInstance();
if (o instanceof TestPrintStream1)
TestPrintStream1 tt = (TestPrintStream1) o;
}编译器在编译这段代码时,当编译到TestPrintStream1 tt = (TestPrintStream1)
o;时,会确定tt的作用域是在try{}的{}中。这明确几点,编译器在编译if语句时,并不对if语句表达式的对错作出判断,程序在执行时才对if语
句表达式的对错做判断。还有就是编译器编译代码是顺序编译的。(这都是编译原理中的知识,这里要用到这些知识来解决这个问题)当编译器编译
TestPrintStream1 tt = (TestPrintStream1)
o;时,编译器不能确定是否会生成tt对象(因为if语句表达式的对错没有确定)并且编译器不能确定这句后是否会用到tt对象。这样就有可能出现:tt对
象没有生成(if表达式错),而在TestPrintStream1 tt = (TestPrintStream1)
o;的后面又要用到tt对象,这样程序会出错,也可能出现其他其他三种情况。但这已经不重要了,因为有了这种情况,tt的定义已经出现了歧义,所以编译器
无法编译。这有很多解决方法。
在做些说明:像以上的代码形式,
{
int j = 0;
if (j == 0)
int i = 1;
}
在C、 c++
和C#中都是正确的,即使在Vs2005中这样的Java代码也是正确的,因为这种形式的代码在不同的编译方法中会有不同的解释(比如这样的形式 i
的作用域被默认为与if(){}形式中的一样。那么这样的形式就会正确)。从这可以看出,1、编写代码时,尽可能的与规范靠拢,2.熟悉自己用得编译器
总结:
为了我们的代码安全,养成良好的编码习惯,及时if后面只有一个语句,我们也要加上大括号,for循环也一样。
原文地址:http://topic.csdn.net/u/20080825/18/34F53E23-ECBC-4A91-B8B5-8C7F2A07F50A.html
测试的代码如下[/b]:
public class TestPrintStream1 {
public static void main(String[] args) {
Class c = TestPrintStream1.class;
try {
Object o = c.newInstance();
if (o instanceof TestPrintStream1)
TestPrintStream1 tt = (TestPrintStream1) o;// 这里为什么会报错呢,说tt 和 TestPrintStream1不能不解析
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
那一行为什么会报错呢?if语句后面不是允许不加大括号吗?
2楼 java2000.net[/b]
if ()
后面不使用花括号时,里面不能出现声明,因为那个涉及到作用域,而没有花括号又没有作用域了。
个人理解。
boolean ok = true;
if(ok)
MyClass c = new MyClass();
这样也是不允许的。
改成
MyClass c = null;
if(ok)
c = new MyClass();
这样是可以的
这个代码问题和 instanceof 没有任何关系
6楼 segazk
Java 把 Test tt = new Test(); 当两条语句看待了相当于 Test tt; tt = new Test();
Eclipse 中报的语法错误是:
Test cannot be resolved
tt cannot be resolved
cmd 下 javac 没通过编译报的错误是:
D:/Test.java:x: 不是语句
Test tt = new Test();
^
D:/Test.java:x: 需要 ';'
Test tt = new Test();
^
2 错误
20楼 bao110908
Java Language Specification 明确指出局部变量声明的作用范围是在一个
块内,也可以理解为在“{ }”内。for 循环可以不使用“{ }”的,但仅限于
执行语句(其中并不包括变量声明语句)
我们看到的代码是这样的:
01 public class TestPrintStream1 {
02
03 public static void main(String[] args) {
04
05 Class c = TestPrintStream1.class;
06 try {
07 Object o = c.newInstance();
08 if (o instanceof TestPrintStream1)
09 TestPrintStream1 tt = (TestPrintStream1) o;
10 } catch (InstantiationException e) {
11 e.printStackTrace();
12 } catch (IllegalAccessException e) {
13 e.printStackTrace();
14 }
15 }
16 }
由于变量作用域的关系,编译器所看到的代码是这样的,注意 09 行的缩进!
01 public class TestPrintStream1 {
02
03 public static void main(String[] args) {
04
05 Class c = TestPrintStream1.class;
06 try {
07 Object o = c.newInstance();
08 if (o instanceof TestPrintStream1)
09 TestPrintStream1 tt = (TestPrintStream1) o;
10 } catch (InstantiationException e) {
11 e.printStackTrace();
12 } catch (IllegalAccessException e) {
13 e.printStackTrace();
14 }
15 }
16 }
从 08 和 09 行编译器所理解的代码中来看,很明显 08 行的 if 语句并没有
结束,因此编译器会认为 if 后面少掉一个语句结束的分号。
笨笨地编译器猜想你的代码应该是这样的,注意 08 行后面的分号
08 if (o instanceof TestPrintStream1);
09 TestPrintStream1 tt = (TestPrintStream1) o;
实际上编译器的这种理解并不是我们想要的。
为了不出现我们所不知的东西来困扰,应该老老实实地在 for, if, while 等语句后面加
上 { },哪怕块中的语句只有一行。
37楼:wargrey
各位,这里有没有熟悉C语言的朋友,相信大家都知道,在C语言里,变量的声明都是要出现在作用域的第一条非赋值语句前的。所以java也是c风格的语言,
它也可能有类似的很细节的规则,就是,java的变量声明必须是一条语句。而java的每个作用域里面的语句分割符是“;”,if (true)
statemenet;只是一条语句,并且如12楼所说,javac提示缺少;,因为它认为声明是一条新语句,而这里却不是。另一个方面javac在解析
到单行if时会假设后面应该是个表达式之类或语句,而声明不是关键字,所以它报出无法解析。
if (true) new Object(); 并不报错。 但是 if (true) int a; if (true) int a=3;也都报了类似的问题。
接触过vb的朋友也知道,vb有块if语句和行if语句,虽然java没有明确提到,但是if (true)
statemenet;就是行if语句。行内的作用域与if所在作用域相同。因为作用域是由{}决定的。只是lz提到的问题很难碰到(如果严格参考
java规范的化),所有平时也没人会去考虑。当然我无法证明这个作用域究竟是什么!
这是我的理解。
70楼:ZjJ_Sir
try {
Object o = c.newInstance();
if (o instanceof TestPrintStream1)
{
TestPrintStream1 tt = (TestPrintStream1) o;
}
}这样很明确,tt的作用域在if(){}的{}内({}是块作用域的标志)所以程序没有问题,而:
try {
Object o = c.newInstance();
if (o instanceof TestPrintStream1)
TestPrintStream1 tt = (TestPrintStream1) o;
}编译器在编译这段代码时,当编译到TestPrintStream1 tt = (TestPrintStream1)
o;时,会确定tt的作用域是在try{}的{}中。这明确几点,编译器在编译if语句时,并不对if语句表达式的对错作出判断,程序在执行时才对if语
句表达式的对错做判断。还有就是编译器编译代码是顺序编译的。(这都是编译原理中的知识,这里要用到这些知识来解决这个问题)当编译器编译
TestPrintStream1 tt = (TestPrintStream1)
o;时,编译器不能确定是否会生成tt对象(因为if语句表达式的对错没有确定)并且编译器不能确定这句后是否会用到tt对象。这样就有可能出现:tt对
象没有生成(if表达式错),而在TestPrintStream1 tt = (TestPrintStream1)
o;的后面又要用到tt对象,这样程序会出错,也可能出现其他其他三种情况。但这已经不重要了,因为有了这种情况,tt的定义已经出现了歧义,所以编译器
无法编译。这有很多解决方法。
在做些说明:像以上的代码形式,
{
int j = 0;
if (j == 0)
int i = 1;
}
在C、 c++
和C#中都是正确的,即使在Vs2005中这样的Java代码也是正确的,因为这种形式的代码在不同的编译方法中会有不同的解释(比如这样的形式 i
的作用域被默认为与if(){}形式中的一样。那么这样的形式就会正确)。从这可以看出,1、编写代码时,尽可能的与规范靠拢,2.熟悉自己用得编译器
总结:
为了我们的代码安全,养成良好的编码习惯,及时if后面只有一个语句,我们也要加上大括号,for循环也一样。
相关文章推荐
- 简单问题的背后:关于if后不加括号的讨论
- 我也提一个关于递归的问题,代码简单,不绕,希望一起讨论一下~
- 关于if后不加括号的讨论
- 关于verilog中if与case语句不完整产生锁存器的问题
- Java中关于String的简单而又深入的问题!
- 链栈的简单实现及括号匹配问题的链栈解决方法
- 关于SQL Server将一列的多行内容拼接成一行的问题讨论
- 关于if 判断等于0 和‘0’的问题
- 关于mybatis 传入基本参数类型使用if test 判断出错的问题
- (C#)一道看似简单却很难答得完全正确的关于多态的问题
- 关于软件原型方法若干问题的讨论
- 关于SQL Server将一列的多行内容拼接成一行的问题讨论
- 【开放 5月18日 发布】:子数组的最大乘积问题_____问题简单,请思考如何逐步降低时间复杂度,跟帖回复,群内讨论.
- 学习Java的第一步是安装好JDK,写一个Hello World, 其实JDK的学习没有那么简单,关于JDK有两个问题是很容易一直困扰Java程序员的地方:一个是CLASSPATH的问题,其实从原理上来说,是要搞清楚JRE的ClassLoader是如何加
- 关于机器访问自己内网IP的问题讨论
- 关于取款问题 java同步简单的小例子
- 【Expression 序列化】WCF的简单使用及其Expression Lambada的序列化问题初步解决方案(四)——关于Guid的问题
- 关于最小的k个数的讨论(top-k问题)
- 易语言----关于超级网页访问模块 在多线程的使用中 出错的问题 讨论
- 关于SQL Server将一列的多行内容拼接成一行的问题讨论 2000 只能自己写函数