変数の再割り当てを停止する
これらの回答は知的に興味深いものですが、短い簡単な回答は読んでいません。
変数が別のオブジェクトに再割り当てされないようにコンパイラーにしたい場合は、キーワードfinalを使用します。
変数が静的変数、メンバー変数、ローカル変数、引数/パラメーター変数のいずれであっても、効果はまったく同じです。
例
実際の効果を見てみましょう。
2つの変数(argとx)の両方に異なるオブジェクトを再割り当てできる、この単純な方法を考えてみましょう。
// Example use of this method:
// this.doSomething( "tiger" );
void doSomething( String arg ) {
String x = arg; // Both variables now point to the same String object.
x = "elephant"; // This variable now points to a different String object.
arg = "giraffe"; // Ditto. Now neither variable points to the original passed String.
}
ローカル変数をfinalとしてマークします。これにより、コンパイラエラーが発生します。
void doSomething( String arg ) {
final String x = arg; // Mark variable as 'final'.
x = "elephant"; // Compiler error: The final local variable x cannot be assigned.
arg = "giraffe";
}
代わりに、パラメーター変数をfinalとしてマークしましょう。これもコンパイラエラーになります。
void doSomething( final String arg ) { // Mark argument as 'final'.
String x = arg;
x = "elephant";
arg = "giraffe"; // Compiler error: The passed argument variable arg cannot be re-assigned to another object.
}
この話の教訓:
変数が常に同じオブジェクトを指すようにする場合は、変数にfinalをマークします。
引数を再割り当てしない
(任意の言語での)良いプログラミング方法として、呼び出しメソッドによって渡されたオブジェクト以外のオブジェクトにパラメーター/引数変数を再割り当てしないでください。上記の例では、決して行を書かないでくださいarg =
。人間は間違いを犯し、プログラマーも人間なので、コンパイラーに助けを求めましょう。コンパイラがそのような再割り当てを見つけてフラグを付けることができるように、すべてのパラメータ/引数変数を「最終」としてマークします。
振り返ってみると
他の回答で述べたように、配列の終わりを超えて読み取るなどの愚かな間違いをプログラマーが回避できるようにするJavaの元の設計目標を考えると、Javaはすべてのパラメーター/引数変数を「最終」として自動的に強制するように設計されているはずです。つまり、引数は変数であってはなりません。しかし後知恵は20/20のビジョンであり、Javaの設計者たちは当時、彼らの手を完全に満たしていました。
それで、常にfinal
すべての引数に追加しますか?
final
宣言されるすべてのメソッドパラメータに追加する必要がありますか?
- 理論的にはそうです。
- 実際には、違います。
➥ final
メソッドのコードが長いか複雑な場合にのみ追加します。引数がローカル変数またはメンバー変数と間違えられ、場合によっては再割り当てされる可能性があります。
引数を再割り当てしないという慣習に慣れればfinal
、それぞれにを追加する傾向があります。しかし、これは退屈で、宣言を読みにくくしています。
引数が明らかに引数であり、ローカル変数でもメンバー変数でもない短い単純なコードの場合、私はわざわざを追加しませんfinal
。コードが非常に明白で、私や他のプログラマーがメンテナンスやリファクタリングを行ったり、引数変数を引数以外のものと誤って間違えたりする可能性がない場合は、気にしないでください。私自身の作業でfinal
は、引数がローカル変数またはメンバー変数と間違えられる可能性がある、より長いコードまたはより複雑なコードにのみ追加します。
完全性のために追加された別のケース
public class MyClass {
private int x;
//getters and setters
}
void doSomething( final MyClass arg ) { // Mark argument as 'final'.
arg = new MyClass(); // Compiler error: The passed argument variable arg cannot be re-assigned to another object.
arg.setX(20); // allowed
// We can re-assign properties of argument which is marked as final
}