168

次のようなメソッドによく遭遇します。

public void foo(final String a, final int[] b, final Object1 c){
}

最終パラメータを渡さずにこのメソッドを呼び出すとどうなりますか。つまり、後で変更された (したがって final として宣言されていない) Object1 は、このメソッドに問題なく渡すことができます。

4

9 に答える 9

220

Javaは、パラメーターをメソッドに送信する前に、常にパラメーターのコピーを作成します。これは、ファイナルが呼び出し元のコードに違いを意味しないことを意味します。これは、メソッド内で変数を再割り当てできないことを意味するだけです。

最終オブジェクトがある場合でも、オブジェクトの属性を変更できることに注意してください。これは、Javaのオブジェクトが実際にはオブジェクトへのポインタであるためです。そして、実際のオブジェクトではなく、ポインタのみがコピーされます(そして、メソッドの最後になります)。

于 2010-02-10T12:08:28.333 に答える
94

final として宣言する必要がある状況があります。そうしないと、コンパイル エラーが発生します。つまり、それらを無名クラスに渡します。基本的な例:

public FileFilter createFileExtensionFilter(final String extension) {
    FileFilter fileFilter = new FileFilter() {
        public boolean accept(File pathname) {
            return pathname.getName().endsWith(extension);
        }
    };

    // What would happen when it's allowed to change extension here?
    // extension = "foo";

    return fileFilter;
}

修飾子を削除するfinalと、値がランタイム定数であることが保証されなくなるため、コンパイル エラーが発生します。つまり、匿名クラスの外部から値を変更すると、匿名クラスのインスタンスが作成後に異なる動作をすることになります。

于 2010-02-10T12:16:45.837 に答える
63

Javaは値渡しのみです。(またはより良い-値による参照の受け渡し)

したがって、渡された引数とメソッド内の引数は、同じオブジェクト(値)を指す2つの異なるハンドラーです。

したがって、オブジェクトの状態を変更すると、それを参照している他のすべての変数に反映されます。ただし、新しいオブジェクト(値)を引数に再割り当てした場合、このオブジェクト(値)を指す他の変数は再割り当てされません。

于 2010-02-10T12:08:01.987 に答える
48

The final keyword on a method parameter means absolutely nothing to the caller. It also means absolutely nothing to the running program, since its presence or absence doesn't change the bytecode. It only ensures that the compiler will complain if the parameter variable is reassigned within the method. That's all. But that's enough.

Some programmers (like me) think that's a very good thing and use final on almost every parameter. It makes it easier to understand a long or complex method (though one could argue that long and complex methods should be refactored.) It also shines a spotlight on method parameters that aren't marked with final.

于 2013-08-09T22:50:40.243 に答える
23

この foo() の実装を考えてみましょう:

public void foo(final String a) {
    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            System.out.print(a);
        }
    }); 
}

Runnableインスタンスはメソッドよりも長く存続するため、これはfinalキーワードなしではコンパイルされません --final参照のコピーを取得しても安全であることをコンパイラに伝えます (後で参照するため)。したがって、valueではなく、 final と見なされるのは参照です。言い換えれば、発信者として、何も台無しにすることはできません...

于 2010-02-10T12:14:21.813 に答える
2

finalは、一度割り当てられた変数の値を変更できないことを意味します。

一方、これらのメソッドの引数にfinalを使用すると、メソッドの実行中にプログラマが値を変更できなくなります。これは、メソッド内で最終変数を再割り当てできないことを意味するだけです。

于 2015-03-18T03:45:20.570 に答える
0

文字列は不変であるため、実際には後で文字列を変更することはできません (文字列オブジェクトを保持していた変数が別の文字列オブジェクトを指すようにすることしかできません)。

finalただし、それが変数をパラメーターにバインドできる理由ではありません。すべてのコンパイラ チェックは、パラメーターがメソッド内で再割り当てされていないことです。これはドキュメンテーションの目的に適しており、間違いなく良いスタイルであり、速度のためにバイトコードを最適化するのにも役立ちます (ただし、これは実際にはあまり効果がないようです)。

ただし、メソッド内でパラメーターを再割り当てしても、Java はすべてのパラメーターを値渡しするため、呼び出し元はそれに気づきません。シーケンスの後

  a = someObject();
  process(a);

a のフィールドは変更されている可能性がありますが、 a は以前と同じオブジェクトのままです。参照渡し言語では、これは当てはまらない場合があります。

于 2010-02-10T12:15:11.207 に答える