2011-11-16 4 views
19

次のプログラムは、それ自身の重要性はありません。以下に示すように、クラスカウンタ内の静的フィールドを使用してforループを使用して作成されたオブジェクトの数を数えます。Javaでのオブジェクト作成文では、単一行のループを使用できません。どうして?

package temp; 

final class Counter 
{ 
    private static int cnt; 

    public Counter() 
    { 
     cnt++; 
    } 

    public static int show() 
    { 
     return(cnt); 
    } 
} 

final public class Main 
{ 
    public static void main(String[] args) 
    { 
     for (int i=0;i<50;i++) 
     { 
      Counter counter=new Counter(); 
     } 

     /*for (int i=0;i<50;i++) 
      Counter counter=new Counter();*/ 

     System.out.print("\nNumber of objects constructed:->"+Counter.show()+"\n\n"); 
    } 
} 

ここでの唯一の問題は、(同じことがまた、whileループに適用される)、コンパイルの原因とまったく動作しないループのためのコメントは、ループの上記と同じ意味であります"ステートメントではない"がこの特定の状況では、forループに1つのステートメントのみが含まれていても、中括弧のペアは必須であることを意味します。どうして?

答えて

27

をこの問題が発生した理由を理解するには、言語仕様にJava's Blocks and Statements syntaxを見ています。

としてA ForStatementが定義されている

:この内、

Block: 
    { BlockStatementsopt } 

BlockStatements: 
    BlockStatement 
    BlockStatements BlockStatement 

BlockStatement: 
    LocalVariableDeclarationStatement 
    ClassDeclaration 
    Statement 

あなたはそれに気付くでしょう:ブロックを見て、その後

Statement: 
    StatementWithoutTrailingSubstatement 
    LabeledStatement 
    IfThenStatement 
    IfThenElseStatement 
    WhileStatement 
    ForStatement 

StatementWithoutTrailingSubstatement: 
    Block 
    EmptyStatement 
    ExpressionStatement 
    SwitchStatement 
    DoStatement 
    BreakStatement 
    ContinueStatement 
    ReturnStatement 
    SynchronizedStatement 
    ThrowStatement 
    TryStatement 

:声明は次のように定義されて

ForStatement: 
    for (ForInitopt ; Expressionopt ; ForUpdateopt) 
     Statement 

LocalVariableDeclarationStatementは、ブロック内にない限り有効ではありません。しかし、ForStatementにはステートメントが続く必要があるため、式を有効にするには括弧が必要です。そのため、ローカル変数宣言は、大括弧なしのループでは無効になります。

+1

+1これをJLSから掘り起こすために+1します。 –

+2

JasCavには正しいことがあります。宣言文は、標準的な命令文と同じではなく、ループ本体として単独では使用できません(if/elseの本体ではない可能性があります)。 –

6

スコープ変数を作成しているためです。 Javaは、これが何もしないということは、メモリを割り当てることであり、ループが再び通過すると、そのループを失い、新しいものを作成するためです。本質的にループ全体はNOPです。なぜなら、何もしていないステートメントに還元されるということです。

ループがNOPであるということは、ループ内の宣言がNOPであることを意味します。

中括弧が存在するため、コンパイラはスコープ内の使用状況を検査しないため、中括弧を使用するバージョンが機能するのはその理由です。これはおそらく、1つの行から生成された解析木と、完全なループスコープがあるときに作成された解析木との関係です。

+2

+1これは、コンパイラ*が2番目のケースで何もしていないことを知っていて、あなたに伝えているからです。最初はそうではありません。 –

+2

それは当てはまりません。コンストラクタは静的カウンタをインクリメントするので、 'new Counter()'は副作用があり、NO-OPではありません。 –

+0

@BrianRoachこれをクリアしていただきありがとうございます。私はOOP言語用のコンパイラを書いたことはありませんでしたが、複数のステートメントを持つループで異なるシンボル解決が必要な一方で、1つの行ステートメントではより複雑なスコープは必要ないと考えています。 –

4

@JasCavは右である、しかし、あなたはそれをコンパイルするために取得することができます。

for (int i=0;i<50;i++) 
    new Counter(); 
+0

これは宣言ではないため、これは機能します。 –

4

またそれは括弧なしでこのように動作するように取得することができます。

Counter counter; 
    for (int i = 0; i < 50; i++) 
    counter = new Counter(); 

ないあなたが今までそのようなことをしたいと思いますどのような理由があること。 ステートメントを追加すると実際に制御フローが変更されるため、角かっこを残してというのは実際にはという悪い考えです。

+0

+1は中括弧を残しておくと悪い考えです。 if文と同じです。 for/ifと同じ行に "body"を置くつもりならば、あなたが行ったことの一種のシグナルとしてそれを行うだけです。 –

関連する問題