web-dev-qa-db-ja.com

メソッドパラメータの最終キーワード

私はしばしば次のようなメソッドに遭遇します:

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

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

136
Aly

Javaは、パラメーターをメソッドに送信する前に常にパラメーターのコピーを作成します。これは、ファイナルは呼び出し元コードの違いを意味しないことを意味します。これは、メソッド内で変数を再割り当てできないことを意味します。 (最終オブジェクトがある場合でも、オブジェクトの属性を変更できることに注意してください)。

174
Thirler

必須 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修飾子を削除すると、値が実行時定数であることが保証されなくなるため、コンパイルエラーが発生します。つまり、匿名クラスの外部から値を変更すると、匿名クラスのインスタンスは、作成後すぐに異なる動作をします。

80
BalusC

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

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

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

52
Bozho

メソッドパラメータのfinalキーワードは、呼び出し側にとってまったく意味がありません。また、実行中のプログラムには絶対に何もないことを意味します。その存在または不在はバイトコードを変更しないからです。メソッド内でパラメーター変数が再割り当てされた場合にのみコンパイラーが文句を言うことを保証します。それで全部です。しかし、それで十分です。

私のような一部のプログラマーは、これを非常に良いことだと考えており、ほぼすべてのパラメーターでfinalを使用しています。長く複雑なメソッドを理解しやすくします(ただし、長く複雑なメソッドはリファクタリングする必要があると主張できます)。また、are n'tfinal

31

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

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

1
SilentKnight

パラメーターをfinalとして宣言した場合、その値を変更することはできません。

class Bike11 {  
    int cube(final int n) {  
        n=n+2;//can't be changed as n is final  
        n*n*n;  
     }  
    public static void main(String args[]) {  
        Bike11 b=new Bike11();  
        b.cube(5);  
    }  
}   

出力:コンパイル時エラー

詳細については、私のブログをご覧ください: http://javabyroopam.blogspot.com

1
Roopam

メソッド入力パラメーターの最後のキーワードは不要です。 Javaは、オブジェクトへの参照のコピーを作成します。そのため、finalを指定してもオブジェクトはfinalにならず、参照のみになり、意味がありません

0
ttati

@stuXnet、正反対の議論をすることができました。オブジェクトを関数に渡し、渡されたオブジェクトのプロパティを変更すると、関数の呼び出し元は変数の変更された値を見ることになります。これは、値による受け渡しではなく、参照システムによる受け渡しを意味します。

紛らわしいのは、エンドユーザーに対してポインターの使用が完全に隠されているシステムでの値渡しまたは参照渡しの定義です。

Javaは、値による受け渡しではないので、渡されたオブジェクトを変更でき、元のオブジェクトは影響を受けません。

プリミティブは変数にしか割り当てることができないので、プリミティブを変更することはできません。そのため、Primitivesを使用した参照渡しまたは値渡しのテストはテストではありません。

他の言語で実行できるJavaでできないことは、Javaにポインターがないため、呼び出し元の変数を新しい値に再割り当てすることです。

0
Armand

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

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

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

  a = someObject();
  process(a);

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

0
Kilian Foth