11

たとえば、変数がありint x = 1、メインスレッドでランナブルを宣言し、ランナブルのメソッドにxを渡したいrun()場合は、宣言する必要がありますfinal。なんで?

final int x = 0;//<----must be final...
private class myRun implements Runnable {

    @Override
    public void run() {
        x++;//
    }

}
4

3 に答える 3

11

それが言語仕様に書かれていることだからです。Guy Steele によるとint x = 0、この選択の背後にある理論的根拠は、プログラマーがメソッド内の宣言がスタック割り当てストレージになることを期待することですがnew myRun()、メソッドから a を返すことができる場合 (またはmyRun、関数の戻り値を超えて a を持続させる場合)、後で変更できxますが、期待するセマンティクスを得るには、代わりにヒープを割り当てる必要があります。

彼らはそれを行うことができましたし、実際に他の言語もそのように行っていました。しかし、Java 設計者は代わりに、実装がスタック割り当てストレージのように見えるヒープ割り当てを要求するのを避けるために、マークを付けるxように要求することにしました。final

(注: これは に固有のものではありませんRunnable。任意の匿名内部クラスに適用されます。)

于 2012-07-11T02:42:53.210 に答える
10

それらを変更できる場合、多くの問題が発生する可能性があるため、次のことを考慮してください。

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 つのオブジェクトを参照できないようにしたいと考えています。ここでは、同期について少し説明します。

これが役に立ったことを願っています!

于 2012-07-11T02:45:30.917 に答える
2

マルチスレッドの大きな「問題」であり、それを使用する全体的な理由は、複数のことが同時に起こっていることです。突然、スレッドがアクセスする、スレッドにとってローカルではない変数の値が、いつでも変更される可能性があります。したがって、次のコードを使用して 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 を作成する必要がありますfinalxの値を別のスレッドから決して変更しないことを「約束」することもできますがfinal、そもそもそれを作成して、コンパイラに助けてもらいませんか? 確かに、 に割り当てられた初期値にしかアクセスできませんがx、変数の初期値にアクセスできることは、変数をまったく使用できないことよりも優れています。あなたのクラス。

于 2012-07-11T02:50:50.450 に答える