10

次のメソッドは、内側のブロックが外側のブロックと同じ名前の変数を宣言しているため、機能しません。どうやら変数は宣言されているブロックではなく、宣言されているメソッドまたはクラスに属しているようです。ちょっとだけ影:

void methodName() {
  int i = 7;
  for (int j = 0; j < 10; j++) {
    int i = j * 2;
  }
}

私がこれまでに使用したほぼすべてのブロック スコープ言語は、これをサポートしていました。これには、学校でインタープリターとコンパイラーを作成した簡単な小さな言語も含まれます。Perl はこれを行うことができ、Scheme や C でさえ可能です。PL/SQL でさえこれをサポートしています!

この Java の設計上の決定の根拠は何ですか?

編集:誰かが指摘したように、Javaにはブロックスコープがあります。私が尋ねている概念の名前は何ですか? それらの言語設計クラスからもっと思い出せたらいいのにと思います。:)

4

6 に答える 6

26

厳密に言えば、Javaにはブロック スコープの変数宣言があります。これはエラーです:

void methodName() {
  for (int j = 0; j < 10; j++) {
    int i = j * 2;
  }
  System.out.println(i); // error
}

'i' は for ブロックの外に存在しないためです。

問題は、Java では、同じメソッドの外部ブロックで宣言された別の変数と同じ名前の変数を作成できないことです。他の人が言っているように、おそらくこれは、特定が難しいバグを防ぐために行われたものです。

于 2008-09-26T19:00:49.957 に答える
19

ライターが意図的にこれを行い、同じ名前の変数が 2 つあることを忘れて完全に台無しにすることは珍しくありません。内部変数名は変更されますが、その変数を使用するコードはそのまま残り、以前はシャドウされていた変数を意図せずに使用するようになりました。これにより、コンパイルはできますが、バグのあるプログラムが実行されます。

同様に、誤って変数を隠してプログラムの動作を変更することも珍しくありません。知らず知らずのうちに既存の変数をシャドウすると、上で述べた変数のシャドウを解除するのと同じくらい簡単にプログラムが変更される可能性があります。

このシャドーイングを許可してもメリットがほとんどないため、危険すぎると除外されました。真剣に、新しい変数を別の名前で呼び出すだけで、問題は解決します。

于 2008-09-26T18:37:34.613 に答える
14

ほとんどの場合、それは意図的なものではなく、プログラミングまたはロジックの欠陥であるという論理的根拠があると思います。

あなたのような些細な例では明らかですが、コードの大きなブロックでは、誤って変数を再宣言することは明らかではない場合があります。

ETA: Java での例外処理に関連している可能性もあります。この質問の一部は、try セクションで宣言された変数が catch/finally スコープで使用できない理由に関連する質問で議論されていると思いました。

于 2008-09-26T18:33:14.953 に答える
10

見つけにくいバグにつながると思います。C#でも同様です。

関数本体の上で変数を宣言する必要があるため、Pascal はこれをサポートしていません。

于 2008-09-26T18:30:51.713 に答える
1

この質問の根底にある仮定は間違っています。

Javaにはブロック レベルのスコープがあります。ただし、スコープの階層もあるため、ループi内では参照できますが、for ループの外では参照できません。forj

public void methodName() {
  int i = 7;
  for (int j = 0; j < 10; j++) {
    i = j * 2;
  }

  //this would cause a compilation error!
  j++;
}

私の人生では、スコープを他の方法で動作させたい理由を理解できません。for ループ内でどちらを参照しているのかを判断することは不可能でiあり、99.999% の確率でiメソッド内で参照したいと考えています。

于 2008-09-26T19:27:25.010 に答える