`
java2000.net
  • 浏览: 651134 次
  • 性别: Icon_minigender_1
  • 来自: 天津
社区版块
存档分类
最新评论

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

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

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

测试的代码如下
  1. public class TestPrintStream1 {
  2.   public static void main(String[] args) {
  3.     Class c = TestPrintStream1.class;
  4.     try {
  5.       Object o = c.newInstance();
  6.       
  7.       if (o instanceof TestPrintStream1)
  8.         TestPrintStream1 tt = (TestPrintStream1) o;// 这里为什么会报错呢,说tt 和 TestPrintStream1不能不解析
  9.     } catch (InstantiationException e) {
  10.       e.printStackTrace();
  11.     } catch (IllegalAccessException e) {
  12.       // TODO Auto-generated catch block
  13.       e.printStackTrace();
  14.     }
  15.   }
  16. }

那一行为什么会报错呢?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.     new Object();
并不报错。

但是
  1. if (true)
  2.      int a;
  3. if (true)
  4.      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循环也一样。










<script type="text/javascript"> </script> <script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript"> </script>
分享到:
评论

相关推荐

    C语言简易计算器(附源码)

    在本项目中,我们讨论的是一个使用C语言编写的简易计算器。C语言是一种基础且强大的编程语言,适合初学者入门并构建各种应用。这个简易计算器的实现,是学习C语言控制流程、函数、输入/输出操作等核心概念的理想实例...

    Python-收集Python中意想不到行为的经典和棘手的例子并讨论究竟发生了什么事情

    本篇文章将深入探讨一些Python中的经典和棘手例子,揭示隐藏在代码背后的逻辑。 1. **变量赋值与引用** Python中的变量赋值并不像C++或Java那样创建副本,而是创建对象引用。这意味着当两个变量指向同一个对象时,...

    数据结构与算法

    - **Java与指针**:虽然Java不支持传统意义上的指针操作,但可以讨论其背后的内存管理机制。 #### 三、数据结构与算法基础 - **数据结构**: - **基本概念**:明确数据结构的基本定义,包括数据的逻辑结构和物理...

    c++面试题

    :` 的使用,它可以在单行中替代简单的 `if-else` 结构。条件运算符的效率可能高于 `if-else`,尤其在编译器优化后。 - 宏内的参数应使用括号包围以防止意外的运算符优先级。例如,`(A) (B)` 防止了 `(A)` 被误解为...

    <计算机程序的构造和解释>第二版中文参考答案

    第一章作为开篇,介绍了Scheme语言的基础语法,并通过简单的语法实践解决较为复杂的数学问题。该章节的核心思想在于引导读者理解过程抽象(procedure abstraction)的概念,即如何通过构造过程抽象来组织和设计程序...

    华为软件编程规范和示例

    根据提供的文件信息,可以看出这份文档主要讨论了华为在软件编程中的规范及具体示例,旨在提升代码质量和可读性。接下来将对文档标题、描述、标签以及部分内容中提及的关键知识点进行详细解读。 ### 华为软件编程...

    Sun_Java语言编码规范(中文版).pdf

    **7.4 if,if-else,if-else-if 语句 (if, if-else, if-else-if Statements)** - `if`语句用于基于条件执行代码。 - `if-else`用于提供两种不同的执行路径。 - `if-else-if`允许根据多个条件执行不同的代码块。 **...

    ANSI C rationale

    - **3.6.2 复合语句或块**:描述了如何使用大括号来创建复合语句。 - **3.6.3 表达式和空语句**:解释了简单的表达式语句和空语句的用法。 - **3.6.4 选择语句**:介绍了`if`、`switch`等控制结构。 - **3.6.5 循环...

    C++面试经典试题-----

    - 使用圆括号来包裹表达式中的操作数和运算符可以避免潜在的优先级问题。 2. **预处理器的计算能力**: - 预处理器能够计算宏定义中的常数表达式的值,因此可以在定义中直接写表达式而非结果。 - 这种做法不仅...

    The_C_Programming_Language(C程序设计语言).pdf

    ### C程序设计语言知识点概述 #### 一、教程简介(Chapter1-...通过系统学习这些知识点,读者不仅可以掌握C语言的基础语法,还能深入理解其背后的原理与思想,为进一步学习高级编程技术打下坚实的基础。

    Esri-2010年IDL培训教材(基于IDL7.1)

    ### Esri-2010年IDL培训教材(基于IDL7.1)知识点解析 #### 一、前言 ...通过对这些知识点的学习,读者不仅能够掌握IDL的基本操作,还能深入了解其背后的原理,从而更高效地进行科学计算和数据分析。

    iOS计算器毕业设计—(包含完整源码可运行).zip

    6. **数学逻辑实现**:计算器的核心是其背后的数学逻辑,包括加、减、乘、除以及括号处理等。这部分通常由一系列函数实现,这些函数会接收输入的数字和运算符,返回计算结果。 7. **内存管理**:Swift使用Automatic...

    Leetcode-note:刷题笔记

    1. 先易后难:从简单的题目开始,逐步过渡到复杂的题目,有助于建立信心并巩固基础。 2. 多解法对比:尝试多种解法,理解每种方法的优缺点,提高问题解决的灵活性。 3. 深度理解:深入研究每个题目的解法,不仅仅是...

    lua参考手册.pdf

    如果对Lua设计背后的决定和讨论感兴趣,可以参考Lua官方网站提供的相关论文,了解Lua语言的发展历史和设计理念。 Lua的词法、语法和语义结构是本手册重点介绍的部分,将通过扩展BNF范式来阐述Lua语言的合法标记、...

    CS数学基础

    本节提出了对无限集合理论合理性的质疑,并探讨了这些问题背后的哲学思考和技术挑战。这有助于读者更全面地理解无限集合理论的应用及其限制。 以上是《CS数学基础》的主要知识点概述,希望能帮助读者更好地掌握...

Global site tag (gtag.js) - Google Analytics