最終変数に関する別の質問を見ていて、初期化せずに最終変数を宣言できることに気付きました (空の最終変数)。これを行うことが望ましい理由はありますか?また、それが有利になるのはいつですか?
9 に答える
これは、不変オブジェクトを作成するのに役立ちます。
public class Bla {
private final Color color;
public Bla(Color c) {this.color = c};
}
Bla は不変です (一度作成されると、色は最終的なものであるため変更できません)。ただし、さまざまな色で構築することで、さまざまな Blas を作成できます。
たとえば、この質問も参照してください。
編集
「空白の最終」にはJavaで非常に具体的な意味があることを追加する価値があるかもしれません。これにより、コメントに混乱が生じたようです-Java言語仕様4.12.4を参照してください。
空白の final は、宣言に初期化子がない final 変数です。
次に、コンストラクターでその空白の最終変数を割り当てる必要があります。
クラスの最終プロパティには、オブジェクトが作成される前に値が割り当てられている必要があります。したがって、それらに値を割り当てることができる最後のポイントはコンストラクターです。
これは不変オブジェクトによく使用されます。
public class Foo {
private final Bar bar;
public Foo(Bar bar) {
this.bar = bar;
}
public Bar getBar() {
return new Bar(bar);
}
}
これは、オブジェクトのインストルメンテーションの前に値がわからない場合に実行できます。コンストラクターに値を割り当てる必要があるだけです。
これは、不変オブジェクトを作成する方法であり、ビルダー パターンで使用されます。
class Builder{
final BuilderContext context;
private Builder(BuilderContext context){
this.context=context;
}
public static Builder New(){
return new Builder(new BuilderContext());
}
空白の最終変数は、コンストラクターの「どこかに」割り当てる必要があります。かなり構築された例:
public class Test {
final int sign;
public Test(String upDown) {
if (upDown.equals("up")) {
sign = +1;
} else {
sign = -1;
}
}
}
1 つのケースは、final を宣言したいフィールドがあるが、その割り当てが例外をスローする可能性があり、それが発生した場合にアクションを実行できるようにしたい場合です。
class A {
final URLConnection conn;
A(String url) {
try {
this.conn = new URL(url).openConnection();
} catch (IOException | MalformedURLException e) {
// Maybe this isn't fatal, so just handle the Exception
// here and move on happily
}
}
}
final
変数を初期化せずに宣言できることに気付きました
空のままにならないように、後で (コンストラクターなどで) 初期化する必要があります。
ウィキペディアより
Java 1.1 で導入された空白の final は、宣言に初期化子がない final 変数です。空白のファイナルは 1 回だけ割り当てることができ、割り当てが発生したときに割り当てを解除する必要があります。これを行うために、Java コンパイラはフロー分析を実行して、空白の最終変数への代入ごとに、その変数が代入前に確実に未代入であることを確認します。そうしないと、コンパイル時エラーが発生します。
一般に、Java コンパイラは、値が割り当てられるまで空白の final が使用されないようにし、値が割り当てられると、現在の final 変数に別の値を再割り当てできないようにします。
状態を導出するメソッドには非常に便利です。クリーンな実行パスを提供し、状態変数が一度だけ割り当てられるようにします。例えば:
public boolean isEdible() {
final boolean edible;
if (vegetable) {
edible = true;
} else if (animal) {
if (vegetarian) {
edible = false;
} else {
edible = true;
}
}
System.out.println("Is edible: " + edible);
return edible;
}