ArrayList(または他のコレクション)を最終的にすることで得られるメリット/デメリットはどれですか? ArrayListに新しい要素を追加し、要素を削除して更新できます。しかし、それが最終的なものになる効果は何ですか?
しかし、それが最終的なものになる効果は何ですか?
これは、異なるコレクションインスタンスを指すように変数を再バインドできないことを意味します。
_final List<Integer> list = new ArrayList<Integer>();
list = new ArrayList<Integer>(); // Since `list' is final, this won't compile
_
スタイルの問題として、私はfinal
として変更するつもりがないほとんどの参照を宣言します。
ArrayListに新しい要素を追加し、要素を削除して更新できます。
必要に応じて、 Collections.unmodifiableList()
を使用して挿入、削除などを防ぐことができます。
_final List<Integer> list = Collections.unmodifiableList(new ArrayList<Integer>(...));
_
これは、参照を再割り当てできないことを意味します。以下のようなことをしようとすると、コンパイラエラーが発生します。
_final List<String> list = new ArrayList<String>();
list = new LinkedList<String>();
^
Compiler error here
_
不変のリストが本当に必要な場合は、Collections.unmodifiableList()
メソッドを使用する必要があります。
たとえば、new ArrayList
を使用して参照を変更することはできません。
final
は、マルチスレッド化の下で多くの結果をもたらします。
final
フィールドの初期化の完了が保証されていることを明確に定義しています。明確に定義されていないのは:
変数final
を作成すると、そのオブジェクト参照が割り当てられた後、そのオブジェクト参照を再割り当てできなくなります。あなたが言及したように、あなたはまだ変更を加えるためにそのリストメソッドを使用することができます。
final
キーワードと Collections.unmodifiableList を組み合わせて使用すると、おそらく達成しようとしている動作を取得できます。たとえば:
final List fixedList = Collections.unmodifiableList(someList);
このため、fixedList
が指すリストは変更できません。ただし、someList
参照を介して変更できることに注意してください(したがって、この割り当て後はスコープ外であることを確認してください)。
当然のことながら、ArrayListでできることには影響しません。ArrayList自体は変更可能です。参照を不変にしました。
ただし、変数をfinalにすることには、他の利点もあります。
final
を作成すると、コンパイラが特定のパフォーマンスの最適化を行うのに役立ちます。一般に、不変にするものが多ければ多いほど良いです。したがって、参照が最終的なものであっても(それらが可変オブジェクトへの参照であっても)一般的には良いアイデアです。
本当に不変のリストを取得するには、リストの内容の詳細コピーを作成する必要があります。 UnmodifiableListは、参照のリストを多少不変にするだけです。リストまたは配列のディープコピーを作成することは、サイズが大きくなるにつれてメモリ上で困難になります。シリアライゼーション/デシリアライゼーションを利用して、配列/リストのディープコピーを一時ファイルに保存できます。メンバー変数は不変である必要があるため、セッターは使用できません。ゲッターは、メンバー変数をシリアル化してファイルにし、それをデシリアライズしてディープコピーを取得します。シリアル化には、オブジェクトツリーの深部に入るという本質的な性質があります。ただし、これにより、ある程度のパフォーマンスコストで完全な不変性が保証されます。
package com.home.immutable.serial;
import Java.io.File;
import Java.io.FileInputStream;
import Java.io.FileNotFoundException;
import Java.io.FileOutputStream;
import Java.io.IOException;
import Java.io.ObjectInputStream;
import Java.io.ObjectOutputStream;
import Java.util.ArrayList;
import Java.util.List;
public final class ImmutableBySerial {
private final int num;
private final String str;
private final ArrayList<TestObjSerial> immutableList;
ImmutableBySerial(int num, String str, ArrayList<TestObjSerial> list){
this.num = num;
this.str = str;
this.immutableList = getDeepCloned(list);
}
public int getNum(){
return num;
}
public String getStr(){
return str;
}
public ArrayList<TestObjSerial> getImmutableList(){
return getDeepCloned(immutableList);
}
private ArrayList<TestObjSerial> getDeepCloned(ArrayList<TestObjSerial> list){
FileOutputStream fos = null;
ObjectOutputStream oos = null;
FileInputStream fis = null;
ObjectInputStream ois = null;
ArrayList<TestObjSerial> clonedObj = null;
try {
fos = new FileOutputStream(new File("temp"));
oos = new ObjectOutputStream(fos);
oos.writeObject(list);
fis = new FileInputStream(new File("temp"));
ois = new ObjectInputStream(fis);
clonedObj = (ArrayList<TestObjSerial>)ois.readObject();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
try {
oos.close();
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return clonedObj;
}
}
私はクラスのコレクションフィールドをfinal
としてマークし、クラスのユーザーがnullかどうかをチェックしないようにします。これは、値が既に最終変数に割り当てられていると、nullなどの別の値に再割り当てできないためです。
FinalはJavaのキーワードまたは予約語であり、Javaのメンバー変数、メソッド、クラス、およびローカル変数に適用できます。 Javaで最終変数を再初期化しようとすると、コンパイラはこれを確認し、コンパイルエラーを発生させます。
Aixが言ったように、別のコレクションに再バインドすることはできません。
例:不変リストの実装と組み合わせて、安全なメンバーを取得し、それを公開できます。
例:参照が変更されないことに依存している場合、finalが必要です。これは、たとえば同期シナリオに当てはまります。
さらに多くの例があります。参照をまったく変更しない場合は、メンバーを最終的に宣言するのが良いスタイルです。
基本的にここで達成しようとしているのは、リストを不変にすることです。ただし、リスト参照を最後にマークすると、参照がこれ以外のリストオブジェクトを指すことはできません。
最終的な(不変の)ArrayListが必要な場合は、代わりにCollectionsクラスのユーティリティメソッドCollections.unmodifaibleList(list)を使用します。
私はこの同じ質問を考え、コーディングし、さらに別の角度から説明に追加する例を考えました。
最終的なarrayListは引き続き変更できます。以下の例を参照して実行し、自分で確認してください。
ここに不変のList宣言を持つ不変のクラスがあります:
public final class ImmutableClassWithArrayList {
final List<String> theFinalListVar = new ArrayList<String>();
}
そして、ここにドライバーがあります:
public class ImmutableClassWithArrayListTester {
public static void main(String[] args) {
ImmutableClassWithArrayList immClass = new ImmutableClassWithArrayList();
immClass.theFinalListVar.add("name");
immClass.theFinalListVar.forEach(str -> System.out.println(str));
}
}
ご覧のとおり、主な方法はリストの追加(変更)です。そのため、注意すべき唯一のことは、コレクションタイプのオブジェクトへの「参照」を別のそのようなオブジェクトに再割り当てできないことです。上記のadarshrによる答えのように、immClass.theFinalListVar = new ArrayList();はできません。ここのメインメソッドで。
変更部分はこれを本当に理解するのに役立ち、同じように役立つことを願っています。