たとえば、変数がありint x = 1
、メインスレッドでランナブルを宣言し、ランナブルのメソッドにxを渡したいrun()
場合は、宣言する必要がありますfinal
。なんで?
final int x = 0;//<----must be final...
private class myRun implements Runnable {
@Override
public void run() {
x++;//
}
}
それが言語仕様に書かれていることだからです。Guy Steele によるとint x = 0
、この選択の背後にある理論的根拠は、プログラマーがメソッド内の宣言がスタック割り当てストレージになることを期待することですがnew myRun()
、メソッドから a を返すことができる場合 (またはmyRun
、関数の戻り値を超えて a を持続させる場合)、後で変更できx
ますが、期待するセマンティクスを得るには、代わりにヒープを割り当てる必要があります。
彼らはそれを行うことができましたし、実際に他の言語もそのように行っていました。しかし、Java 設計者は代わりに、実装がスタック割り当てストレージのように見えるヒープ割り当てを要求するのを避けるために、マークを付けるx
ように要求することにしました。final
(注: これは に固有のものではありませんRunnable
。任意の匿名内部クラスに適用されます。)
それらを変更できる場合、多くの問題が発生する可能性があるため、次のことを考慮してください。
public void count()
{
int x;
new Thread(new Runnable()
{
public void run()
{
while(x < 100)
{
x++;
try
{
Thread.sleep(1000);
}catch(Exception e){}
}
}
}).start();
// do some more code...
for(x = 0;x < 5;x++)
for(int y = 0;y < 10;y++)
System.out.println(myArrayElement[x][y]);
}
これは大まかな例ですが、原因不明のエラーが多く発生する可能性があることがわかります。これが、変数が final でなければならない理由です。上記の問題の簡単な修正方法を次に示します。
public void count()
{
int x;
final int w = x;
new Thread(new Runnable()
{
public void run()
{
int z = w;
while(z < 100)
{
z++;
try
{
Thread.sleep(1000);
}catch(Exception e){}
}
}
}).start();
// do some more code...
for(x = 0;x < 5;x++)
for(int y = 0;y < 10;y++)
System.out.println(myArrayElement[x][y]);
}
より完全な説明が必要な場合は、同期のようなものです。Java は、複数のスレッドから 1 つのオブジェクトを参照できないようにしたいと考えています。ここでは、同期について少し説明します。
これが役に立ったことを願っています!
マルチスレッドの大きな「問題」であり、それを使用する全体的な理由は、複数のことが同時に起こっていることです。突然、スレッドがアクセスする、スレッドにとってローカルではない変数の値が、いつでも変更される可能性があります。したがって、次のコードを使用して 1 ~ 10 の数字を出力しているだけかもしれません。
int x = 0; //supposing that this was allowed to be non-final...
private class myRun implements Runnable{
@Override
public void run() {
for (int i=0; i<10; i++ ) {
System.Out.Println( x++ );
}
}
}
しかし実際には、そのクラスの他のコードが x の値を変更すると、230498 - 230508 を出力する可能性があります。x の値は、ループの途中で変更される可能性があります。x
特定の値を持つこと、または以前に割り当てた値を保持することに依存できない場合、コードでそれを使用しても無駄になります。変数の内容が一瞬で変わる可能性があるのに、なぜ変数を使用するのでしょうか?
Java では、使用をまったく禁止するだけでなく、Java を作成する必要がありますfinal
。x
の値を別のスレッドから決して変更しないことを「約束」することもできますがfinal
、そもそもそれを作成して、コンパイラに助けてもらいませんか? 確かに、 に割り当てられた初期値にしかアクセスできませんがx
、変数の初期値にアクセスできることは、変数をまったく使用できないことよりも優れています。あなたのクラス。