`
阿尔萨斯
  • 浏览: 4185043 次
社区版块
存档分类
最新评论

简单问题的背后:关于if后不加括号的讨论

 
阅读更多
看上去一个很简单的问题,结果却不是想象中的那样。良好的编码习惯是多么的重要啊

原文地址:http://topic.csdn.net/u/20080825/18/34F53E23-ECBC-4A91-B8B5-8C7F2A07F50A.html

测试的代码如下
  1. publicclassTestPrintStream1{

  2. publicstaticvoidmain(String[]args){

  3. Classc=TestPrintStream1.class;
  4. try{
  5. Objecto=c.newInstance();
  6. if(oinstanceofTestPrintStream1)
  7. TestPrintStream1tt=(TestPrintStream1)o;//这里为什么会报错呢,说tt和TestPrintStream1不能不解析
  8. }catch(InstantiationExceptione){

  9. e.printStackTrace();
  10. }catch(IllegalAccessExceptione){
  11. //TODOAuto-generatedcatchblock
  12. e.printStackTrace();
  13. }

  14. }
  15. }

那一行为什么会报错呢?if语句后面不是允许不加大括号吗?

2楼 java2000.net

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时会假设后面应该是个表达式之类或语句,而声明不是关键字,所以它报出无法解析。
  1. if(true)
  2. newObject();


并不报错。

但是
  1. if(true)
  2. inta;

  3. if(true)
  4. inta=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循环也一样。
分享到:
评论

相关推荐

    表达式的括号匹配检验问题

    假设在表达式中允许有三种括号:圆括号、方括号...要求设计测试数据,如果在表达式中括号使用正确,输出结果为“此表达式中括号匹配合法”,否则输出结果为“此表达式中括号匹配不合法”,#为表达式的起始和结束标志。

    批处理:删除文件名中两个括号(小中大各种组合)及之间的内容?待检验.txt

    批处理:删除文件名中两个括号(小中大各种组合)及之间的内容?待检验批处理:删除文件名中两个括号(小中大各种组合)及之间的内容?待检验

    括号匹配检验_括号匹配检验_括号匹配程序_

    利用栈编写满足下列要求的括号匹配检验程序:假设表达式中允许包含两种括号:圆括号和方括号,其嵌套的顺序随意,即([]())或[([][])]等为正确的格式,[(]或([())或(()])均为不正确的格式。输入一个包含上述括号的...

    括号匹配问题

    假设表达式中允许包含3种括号:圆括号,方括号和大括号。设计一个算法采用顺序栈判断表达式中的括号是否正确配对。

    数字加括号等功能

    专利撰写过程中,需要对特征进行编号,此工具就是将数字进行编号,同时对于权利要求书中的特征需要进行加括号操作,本工具也可以进行一键尖括号操作,本文件为宏文件,可以直接导入Word中使用。 功能:按表替换、加...

    矩阵连乘问题实现(最佳加括号方式-动态规划算法)

    矩阵连乘问题分析和实现用于动态规划 最佳加括号方式-动态规划算法

    c++括号匹配问题 c++括号匹配问题

    c++括号匹配问题c++括号匹配问题c++括号匹配问题c++括号匹配问题c++括号匹配问题c++括号匹配问题c++括号匹配问题c++括号匹配问题

    详解:Bash Shell 脚本中的括号:()、(( ))、[ ]、[[ ]]、{ } 及 他们使用的运算符!

    文章目录1、小括号 ——( ):1.1、作用:1.2、关于 ( ) 中使用的运算符:2、双小括号 —— (( )):2.1、作用:2.2、关于 (( )) 中使用的运算符:3、Bash 内部命令 —— [ ] :3.1、作用:3.2、关于 [ ] 中使用的...

    判断左右括号是否匹配

    问题:有一个数组里面存放了很多的字符,需要判断这一串字符里面的括号是否匹配。

    括号匹配问题(用C实现的,可用win-tc/tc运行)

    假设一个算术表达式中可包含三种括号:圆括号,方括号和花括号且这三种括号可按任意次序嵌套使用。试利用栈的运算,编写判别给定表达式中所含括号是否正确配对出现的(可也直接运行,而且简单易懂)

    IDEA花括号插件

    插件作用为使得距离较近的括号用不同的颜色区分开来。让你的代码结构更加清晰,不在为找括号而烦恼。

    数据结构 括号匹配问题 c源文件

    给定一个字符串,其中的字符只包含三种...括号匹配要求括号必须以正确的顺序配对,如 “{ [ ] ( ) }” 或 “[ ( { } [ ] ) ]” 等为正确的格式,而 “[ ( ] )” 或 “{ [ ( ) }” 或 “( { } ] )” 均为不正确的格式。

    浅谈js中调用函数时加不加括号的问题

    其实总结起来如下: 函数只要是要调用它进行执行的,都必须加括号。此时,函数()实际上等于函数的返回值。当然,有些没有返回值,但已经执行了函数体内的...另外:除了两边不加括号,也可以两边都加括号来实现函数的拷

    括号嵌套问题课程设计

    某个序列完全由圆括号组成,一个“(”和“)”称为一对括号,且序列中的括号成对出现。设n为序列中出现的括号对数,k为序列中括号的最大嵌套深度;那么,序列“((()()()))()(())”的n为8,k为3,请...

    详谈构造函数加括号与不加括号的区别

    //实例化对象,下面这两个如果构造函数没有形参的话,实例化的时候构造函数可以不加括号(推荐加上); var p = new Hello; var p1 = new Hello(); //但是用下边的方式调用getName函数的时候,构造函数有没有...

    Java程序设计基础:if单分支语句.pptx

    代码块只有一条语句时,大括号可以省略,但并不建议 示例: 单分支if语句的使用 可理解为: if(半径大于等于0 ){ 计算圆的面积 } 如果圆半径大于等于0,就可以计算圆的面积。 单分支if语句的使用 public class ...

    括号匹配 验证 缺少括号 括号不匹配

    缺少左括号 缺少右括号 括号数目相等但不匹配 等等 用栈实现

    括号嵌套问题(非括号匹配)

    括号嵌套问题(非括号匹配),输入括号序列,求出嵌套深度和括号对数

Global site tag (gtag.js) - Google Analytics