IV. コレクションクラスの操作と共通メソッド
A. コレクションの反復処理
コレクションの走査は、コレクション内の要素に 1 つずつアクセスして処理する操作です。Java では、コレクションはいくつかの方法で走査できます。
- イテレータの使用 (Iterator): イテレータは、コレクション フレームワークによって提供される要素を走査する方法であり、Iterable インターフェイスを実装するすべてのコレクション クラス (List、Set など) に適用できます。イテレータ オブジェクトは、コレクション オブジェクトの iterator() メソッドを呼び出して取得できます。その後、while ループと next() メソッドを使用して、すべての要素が走査されるまでコレクション内の要素に順次アクセスします。
Iterator<T> iterator = collection.iterator(); while (iterator.hasNext()) { T element = iterator.next(); // 对元素进行处理 }
- 拡張 for ループ (foreach ループ) を使用する: 拡張 for ループは、コレクションの走査を簡略化するために Java 5 によって導入された構文であり、Iterable インターフェースを実装するすべてのコレクション クラスに適用できます。拡張された for ループを使用して、反復子を使用せずにコレクション内の要素を直接走査します。
for (T element : collection) { // 对元素进行处理 }
- ラムダ式とストリーム API の使用 (Java 8 以降): Java 8 で導入されたラムダ式とストリーム API は、より簡潔で強力なコレクション操作メソッドを提供します。コレクションをストリームに変換すると、一連の中間操作と最終操作を使用してコレクション内の要素を処理できます。
collection.stream() .filter(condition) .map(mapper) .forEach(action);
異なるシナリオや要件には異なるトラバース方法が適していることに注意してください。トラバース方法を選択するときは、特定の状況に応じて最適な方法を選択できます。さらに、コレクションを同時に変更する場合は、トラバーサル プロセス中にコレクションを変更できるかどうか、および異常または不確実な結果を回避するために同時実行制御が必要かどうかに注意する必要があります。
B. 要素の追加と削除
Java では、次のメソッドを使用して、コレクションに要素を追加したりコレクションから要素を削除したりできます。
-
要素を追加します:
- add() メソッドの使用: コレクションの add() メソッドを呼び出すことにより、コレクションの末尾に要素を追加できます。
collection.add(element);
- addAll() メソッドの使用: コレクションの addAll() メソッドを呼び出すことにより、別のコレクション内のすべての要素を現在のコレクションに追加できます。
collection.addAll(anotherCollection);
- 特定の位置 (List インターフェイスなど) で add() メソッドを使用する: List インターフェイスを実装するコレクションの場合、add(index, element) メソッドを使用して、指定された位置に要素を挿入できます。
list.add(index, element);
- add() メソッドの使用: コレクションの add() メソッドを呼び出すことにより、コレクションの末尾に要素を追加できます。
- 要素を削除します:
- Remove() メソッドを使用する: コレクションの Remove() メソッドを呼び出すことにより、コレクション内の指定された要素を削除できます。コレクション内に同一の要素が複数ある場合、最初に一致した要素のみが削除されます。
collection.remove(element);
- RemoveAll() メソッドの使用: コレクションの RemoveAll() メソッドを呼び出すことにより、コレクション内の、別のコレクション内と同じ要素をすべて削除できます。
collection.removeAll(anotherCollection);
- 特定の位置 (List インターフェイスなど) で Remove() メソッドを使用する: List インターフェイスを実装するコレクションの場合、remove(index) メソッドを使用して、指定された位置にある要素を削除できます。
list.remove(index);
- clear() メソッドを使用する: コレクションの clear() メソッドを呼び出すと、コレクション内のすべての要素が削除され、コレクションが空のコレクションになります。
collection.clear();
- Remove() メソッドを使用する: コレクションの Remove() メソッドを呼び出すことにより、コレクション内の指定された要素を削除できます。コレクション内に同一の要素が複数ある場合、最初に一致した要素のみが削除されます。
特定のコレクションの種類と要件に応じて、要素を追加および削除する適切な方法を選択する必要があります。さらに、一部の特殊なコレクション実装では、他の特定の追加メソッドと削除メソッドが提供される場合があります。コレクションの特定の実装クラスとドキュメントに従って選択して使用する必要があります。
C. 要素の取得と変更
Java では、次のメソッドを使用してコレクション内の要素を取得および変更できます。
-
要素を取得します:
- get() メソッドを使用する (List インターフェイスなど): List インターフェイスを実装するコレクションの場合、get(index) メソッドを使用して、指定された位置にある要素を取得できます。
T element = list.get(index);
- contains() メソッドを使用する: コレクションの contains() メソッドを呼び出すことにより、コレクションに指定された要素が含まれているかどうかを確認できます。
boolean containsElement = collection.contains(element);
- IndexOf() メソッドを使用する (List インターフェイスなど): List インターフェイスを実装するコレクションの場合、indexOf(element) メソッドを使用して、コレクション内の指定された要素のインデックスを取得できます。
int index = list.indexOf(element);
- get() メソッドを使用する (List インターフェイスなど): List インターフェイスを実装するコレクションの場合、get(index) メソッドを使用して、指定された位置にある要素を取得できます。
-
要素を変更します:
- set() メソッドを使用する (List インターフェイスなど): List インターフェイスを実装するコレクションの場合、set(index, element) メソッドを使用して、指定された位置にある要素を新しい要素に置き換えることができます。
list.set(index, newElement);
- set() メソッドを使用する (List インターフェイスなど): List インターフェイスを実装するコレクションの場合、set(index, element) メソッドを使用して、指定された位置にある要素を新しい要素に置き換えることができます。
D. コレクションに要素が含まれているかどうかを判断する
- contains() メソッドを使用する: コレクションの contains() メソッドを呼び出すことにより、コレクションに指定された要素が含まれているかどうかを確認できます。このメソッドは、コレクションに指定された要素が含まれているかどうかを示すブール値を返します。
- containsAll() メソッドの使用: コレクションの containsAll() メソッドを呼び出すことにより、コレクションに別のコレクション内のすべての要素が含まれているかどうかを確認できます。このメソッドはコレクションをパラメータとして受け取り、そのコレクションに別のコレクション内のすべての要素が含まれているかどうかを示すブール値を返します。
E. コレクションの並べ替えと比較
Java では、次のメソッドを使用してコレクションを並べ替えたり比較したりできます。
-
コレクションを並べ替えます。
- Collections.sort() メソッドを使用する (List インターフェイスなど): List インターフェイスを実装するコレクションの場合、Collections.sort() メソッドを使用してコレクション内の要素を並べ替えることができます。このメソッドは、要素の自然な順序に従って、またはカスタム コンパレータを通じて並べ替えます。
Collections.sort(list);
- TreeSet コレクションを使用する: TreeSet は順序付けされたコレクションであり、要素または Comparator の自然な順序に従って並べ替えられます。コレクションに対して頻繁に並べ替え操作を実行する必要がある場合は、TreeSet を使用してコレクションの順序を維持できます。
TreeSet<T> set = new TreeSet<>(comparator);
- Collections.sort() メソッドを使用する (List インターフェイスなど): List インターフェイスを実装するコレクションの場合、Collections.sort() メソッドを使用してコレクション内の要素を並べ替えることができます。このメソッドは、要素の自然な順序に従って、またはカスタム コンパレータを通じて並べ替えます。
-
コレクションを比較します。
- equals() メソッドを使用します。equals() メソッドを呼び出すと、2 つのコレクションが等しいかどうかを比較できます。このメソッドは、コレクション内の要素が 1 対 1 に対応し、等しいかどうかを比較します。
boolean isEqual = collection1.equals(collection2);
- hashCode() メソッドを使用します。コレクションの hashCode 値を比較することで、2 つのコレクションが等しいかどうかを判断できます。2 つのコレクションの hashCode 値が等しくない場合は、絶対に等しくありません。2 つのコレクションの hashCode 値が等しい場合は、比較と確認のためにさらにquals() メソッドを呼び出す必要があります。
boolean isPossiblyEqual = collection1.hashCode() == collection2.hashCode();
- equals() メソッドを使用します。equals() メソッドを呼び出すと、2 つのコレクションが等しいかどうかを比較できます。このメソッドは、コレクション内の要素が 1 対 1 に対応し、等しいかどうかを比較します。
V. コレクション クラスのパフォーマンスに関する考慮事項
A. 時間計算量と空間計算量
-
配列リスト:
- 原則: ArrayList は配列実装に基づいた動的配列です。自動的にスケールし、ランダム アクセスをサポートします。
- 時間計算量:
- インデックスによる要素へのアクセス: O(1)
- 末尾の要素の追加/削除: O(1) (償却時間計算量は O(1))
- 中間または先頭の要素の追加/削除: 平均 O(n)、最悪の場合 O(n)
- 空間の複雑さ: O(n)
-
リンクされたリスト:
- 原則: LinkedList は二重リンク リストに基づいて実装されます。高速な挿入および削除操作はサポートされますが、ランダム アクセスはサポートされません。
- 時間計算量:
- インデックスによる要素へのアクセス: O(n)
- 末尾の要素の追加/削除: O(1)
- 途中または先頭の要素を追加/削除: O(1)
- 空間の複雑さ: O(n)
-
ハッシュセット:
- 原則: HashSet は、ハッシュ関数を使用して要素を保存場所にマップするハッシュ テーブルに基づいて実装されます。ハッシュ関数とリンクされたリスト/赤黒ツリーを通じてハッシュの衝突を解決します。
- 時間計算量:
- 要素の追加: 平均 O(1)、最悪の場合 O(n)
- 要素の削除: 平均 O(1)、最悪の場合 O(n)
- 要素の検索: 平均 O(1)、最悪のケース O(n)
- 空間の複雑さ: O(n)
-
ツリーセット:
- 原則: TreeSet は、自己平衡二分探索ツリーである赤黒ツリーに基づいて実装されます。要素を順番に保ちます。
- 時間計算量:
- 要素の追加: O(log n)
- 要素の削除: O(log n)
- 要素の検索: O(log n)
- 空間の複雑さ: O(n)
-
ハッシュマップ:
- 原則: HashMap は、ハッシュ関数を使用してキーを保管場所にマップするハッシュ テーブルに基づいて実装されます。ハッシュ関数とリンクされたリスト/赤黒ツリーを通じてハッシュの衝突を解決します。
- 時間計算量:
- 要素の追加: 平均 O(1)、最悪の場合 O(n)
- 要素の削除: 平均 O(1)、最悪の場合 O(n)
- 要素の検索: 平均 O(1)、最悪のケース O(n)
- 空間の複雑さ: O(n)
-
ツリーマップ:
- 原則: TreeMap は、自己平衡二分探索ツリーである赤黒ツリーに基づいて実装されます。鍵を順番に保管します。
- 時間計算量:
- 要素の追加: O(log n)
- 要素の削除: O(log n)
- 要素の検索: O(log n)
- 空間の複雑さ: O(n)
B. 適切なコレクション クラスを選択する
-
機能要件: まず、要素の追加、削除、変更、クエリ操作、ソート要件、検索効率、メモリ使用量などの機能要件を明確にする必要があります。コレクション クラスが異なれば、操作ごとにパフォーマンス特性も異なります。
-
データ構造の特性: さまざまなコレクション クラスのデータ構造の特性を理解することが、適切なコレクション クラスを選択する鍵となります。たとえば、効率的なランダム アクセスと要素のインデックス作成が必要な場合は ArrayList を選択でき、頻繁な挿入と削除操作が必要な場合は LinkedList を選択でき、順序を維持する必要がある場合は TreeSet または TreeMap を選択できます。
-
同時実行要件: アプリケーションにマルチスレッドの同時操作が含まれる場合は、Vector、ConcurrentHashMap などのスレッドセーフなコレクション クラスの選択を検討するか、適切な同期メカニズムを使用してスレッドの安全性を確保する必要があります。
-
要素の重複を排除するか、重複を許可しない必要がある: コレクション内の要素の一意性を保証する必要がある場合は、HashSet または TreeSet を選択できます。要素が追加された順序を保持する必要がある場合は、LinkedHashSet を選択できます。
-
メモリ フットプリントとパフォーマンスの要件: コレクション クラスが異なれば、メモリ フットプリントとパフォーマンスも異なる場合があります。アプリケーションのメモリ要件とパフォーマンス要件を考慮して、適切なコレクション クラスを選択してください。
-
スケーラビリティと柔軟性: 一部のコレクション クラスは、より多くの機能と柔軟性を提供します。たとえば、LinkedHashMap は挿入順に要素を反復する機能を提供しますが、HashMap は提供しません。ニーズに応じて、コレクション クラスの特性と機能を選択します。
最終的な選択は、特定のニーズに基づいて行われ、さまざまな要素を比較検討して、最適なコレクション クラスを選択する必要があります。選択するときは、実際のテストと評価のためにコレクション クラスのドキュメントとパフォーマンス指標を参照できます。
C. コレクションクラスのパフォーマンス比較
-
ArrayList と LinkedList の比較:
- ランダム アクセス: ArrayList は、インデックスによって要素に直接アクセスできるため、LinkedList よりも高速です。
- 挿入と削除: リストの途中または先頭での挿入と削除については、LinkedList の方が ArrayList よりも高速です。
- メモリ使用量: LinkedList は追加のリンク リスト ノードを必要とするため、ArrayList よりも多くのメモリを使用します。
-
ハッシュセットとツリーセット:
- 追加と削除: HashSet は要素の検索にハッシュ テーブルを使用するため、要素の追加と削除が TreeSet よりも高速です。
- ルックアップ: TreeSet は順序付けされており、高速ルックアップにバイナリ検索ツリーを使用できるため、HashSet よりも高速です。
- メモリ使用量: HashSet は要素の順序を維持する必要がないため、通常、TreeSet よりもメモリの使用量が少なくなります。
-
ハッシュマップとツリーマップ:
- 追加と削除: HashMap は要素の検索にハッシュ テーブルを使用するため、キーと値のペアの追加と削除が TreeMap よりも高速です。
- ルックアップ: TreeMap は順序付けされており、高速ルックアップに赤黒ツリーを使用できるため、HashMap よりも高速です。
- メモリ使用量: HashMap はキーの順序を維持する必要がないため、通常、TreeMap よりもメモリの使用量が少なくなります。
VI. Java 8 でのコレクションの改善
A. ストリーム API の概要
Java 8 で導入された Stream API は、コレクション データをストリーム処理する方法を提供する関数型プログラミング スタイルのコレクション操作 API です。以下は、Stream API の概要といくつかのコード例です。
-
ストリームを作成します。
- コレクションからストリームを作成する:ストリームは、
stream()
メソッドまたはコレクションのメソッドを通じて作成できます。parallelStream()
- 配列からストリームを作成する:
Arrays.stream()
このメソッドを使用して、配列のストリームを作成できます。 - Stream の静的メソッドを使用する: Stream クラスには、ストリームを作成するためのいくつかの静的メソッド (
Stream.of()
、Stream.iterate()
など) が用意されていますStream.generate()
。
- コレクションからストリームを作成する:ストリームは、
-
中間操作:
- フィルター:
filter()
メソッドを使用して、条件に基づいてコレクション内の要素をフィルターします。 - マッピング:
map()
メソッドを使用して、コレクション内の要素を別の型にマップします。 - 並べ替え:
sorted()
メソッドを使用して、コレクション内の要素を並べ替えます。 - グループ化とパーティション化:
groupingBy()
、partitioningBy()
などのメソッドを使用して、コレクション内の要素をグループ化またはパーティション化します。
- フィルター:
-
最終操作:
- トラバーサル:
forEach()
このメソッドを使用して、コレクション内の要素を反復処理します。 - 収集:
collect()
メソッドを使用して、ストリーム内の要素をコレクションに収集します。 - 集計操作:
count()
、sum()
、average()
およびその他のメソッドを使用して、コレクション内の要素に対して集計操作を実行します。 - 検索と一致:
anyMatch()
、allMatch()
、noneMatch()
などのメソッドを使用して、コレクション内の要素を検索または一致させます。
- トラバーサル:
Stream API の使用法を示すコード例をいくつか示します。
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
// 示例1:筛选出所有大于5的数字
List<Integer> filteredNumbers = numbers.stream()
.filter(n -> n > 5)
.collect(Collectors.toList());
// 示例2:计算集合中所有偶数的平均值
double average = numbers.stream()
.filter(n -> n % 2 == 0)
.mapToInt(n -> n)
.average()
.orElse(0.0);
// 示例3:将集合中的字符串转换为大写并排序
List<String> strings = Arrays.asList("apple", "banana", "orange");
List<String> uppercaseSorted = strings.stream()
.map(String::toUpperCase)
.sorted()
.collect(Collectors.toList());
これらの例は、Stream API の一般的な使用法をいくつか示しています。特定のニーズに応じて、さまざまな中間操作と最終操作を使用して、コレクション内の要素を処理できます。Stream API を使用すると、コードがより簡潔で読みやすくなり、コレクション データを処理するための関数型プログラミング方法が提供されます。
B. ラムダ式と関数インターフェイスの適用
収集操作:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// 使用Lambda表达式遍历集合
numbers.forEach(n -> System.out.println(n));
// 使用Lambda表达式过滤集合中的元素
List<Integer> filteredNumbers = numbers.stream()
.filter(n -> n % 2 == 0)
.collect(Collectors.toList());
// 使用Lambda表达式对集合进行映射
List<String> mappedStrings = numbers.stream()
.map(n -> "Number: " + n)
.collect(Collectors.toList());
インターフェイスのコールバック:
// 定义一个函数式接口
@FunctionalInterface
interface Callback {
void execute();
}
// 定义一个方法,接受一个回调函数作为参数
static void performAction(Callback callback) {
// 执行回调函数
callback.execute();
}
// 使用Lambda表达式作为回调函数
performAction(() -> System.out.println("Performing action..."));
並列処理:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// 使用并行流和Lambda表达式对集合进行并行处理
numbers.parallelStream()
.forEach(n -> System.out.println(n));
タイミングタスク:
// 使用Lambda表达式创建一个定时任务
ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
executor.schedule(() -> System.out.println("Task executed"), 1, TimeUnit.SECONDS);
GUIイベント処理:
// 使用Lambda表达式处理按钮的点击事件
button.addActionListener(e -> System.out.println("Button clicked"));
C. コレクション クラスの新機能
-
forEach メソッド: コレクション クラスの Iterable インターフェイスには新しい forEach メソッドがあり、Lambda 式をパラメータとして使用して、コレクション内の各要素に対して特定の操作を簡単に実行できます。
-
ストリーム API: Java 8 では、コレクション データをストリーミングする方法を提供する Stream API が導入されました。ストリームは、コレクションに対するフィルター、マップ、並べ替え、集計などの操作に使用できるほか、並列処理もサポートします。
-
関数型インターフェイス: コレクションの操作と処理を簡素化するために、述語、コンシューマー、関数などのいくつかの関数型インターフェイスが導入されています。
-
メソッド参照: メソッド参照を使用して Lambda 式を簡素化し、既存のメソッドを Lambda 式の実装として参照できます。
-
デフォルトのメソッド: Java 8 では、Collection インターフェイスおよびその他のコレクション インターフェイスに、stream、ParallelStream、removeIf などのいくつかのデフォルト メソッドが導入されました。
-
強化された同時コレクション: Java 5 では、スレッドセーフなコレクション操作を提供する ConcurrentHashMap、ConcurrentLinkedQueue などの同時コレクション クラスが導入されています。
-
NavigableMap および NavigableSet: Java 6 では、NavigableMap および NavigableSet インターフェイスが導入されました。これらは、いくつかのナビゲーション メソッドを提供し、範囲クエリや並べ替えなどの操作をサポートします。
-
コレクション ファクトリ メソッド: Java 9 では、不変コレクションを簡単に作成できる List.of、Set.of、Map.of などのいくつかのコレクション ファクトリ メソッドが導入されています。
-
コレクション操作の最適化: Java の以降のバージョンでは、並列処理の効率の向上や中間操作のメモリ消費量の削減など、コレクション操作のパフォーマンスが最適化されています。
VII. ベストプラクティスとよくある質問
A. コレクション クラスのスレッド セーフ
コレクション クラスのスレッド セーフとは、マルチスレッド環境でコレクションが同時にアクセスされた場合に、コレクション操作の正確性と一貫性が保証されることを意味します。Vector
Java には、 、などHashtable
、スレッド セーフなコレクション クラスがいくつか用意されていますConcurrentHashMap
。これらのクラスは、スレッド セーフを確保するための同期メカニズムを内部で実装します。
実際には、コレクション クラスのスレッドの安全性を確保するには、次の点に注意してください。
-
Vector
スレッドセーフなコレクション クラスを使用する: Java によって提供される、ロックHashtable
やConcurrentHashMap
その他の同期メカニズムを内部で実装してスレッドの安全性を確保する、 、 などのスレッドセーフなコレクション クラスを使用することをお勧めします。 -
同期制御を使用する: 非スレッドセーフなコレクション クラスを使用する必要がある場合は、
synchronized
キーワードやReentrantLock
ロック操作などを使用して、明示的な同期制御を使用してスレッドの安全性を確保できます。 -
同時コレクション クラスを使用する: Java は、パフォーマンスを向上させるためにより効率的な同時実行メカニズムを使用する、 などの同時シナリオ用の
ConcurrentHashMap
特別なコレクション クラスをいくつか提供します。ConcurrentLinkedQueue
-
不変コレクションを使用する: 不変コレクションはスレッドセーフであり、
Collections.unmodifiableXXX
メソッドを使用して可変コレクションを不変コレクションに変換して、スレッドの安全性を確保できます。
スレッド セーフに加えて、いくつかの一般的なコレクション スレッド セーフの問題にも注意する必要があります。
-
イテレータの無効化: イテレータを使用してコレクションを走査するときに、他のスレッドがコレクションを変更すると、イテレータが無効になり、例外が
ConcurrentModificationException
スローされることがあります。解決策は、並行コレクション クラスを使用するか、トラバーサル中に同期メカニズムを使用することです。 -
コレクション操作の原子性: 非スレッドセーフなコレクション クラスを使用して複数の操作を組み合わせると、操作間で競合状態が発生し、一貫性のない結果が生じる可能性があります。解決策は、同期メカニズムを使用するか、同時コレクション クラスを使用することです。
-
デッドロック: 明示的な同期制御を使用する場合は、デッドロック、つまり複数のスレッドが互いにロックの解放を待機することを回避するように注意する必要があります。デッドロックは、ロック順序を適切に計画し、ネストされたロックを回避することで防止できます。
つまり、コレクション クラスのスレッド セーフを確保するには、特定のシナリオに従って適切なコレクション クラスまたは同期メカニズムを選択し、一般的なスレッド セーフの問題を回避するように注意する必要があります。マルチスレッド環境でコレクション クラスを使用する場合、プログラムの正確さとパフォーマンスを確保するには、スレッド セーフを慎重に考慮することが重要です。
B. コレクションクラスの容量と負荷率
Java のコレクション クラスでは、容量と負荷係数は、コレクションのストレージと拡張戦略を制御するための重要なパラメータです。
容量 (Capacity) は、コレクション内の要素を格納するために使用される基礎となる配列のサイズを指します。、 などHashMap
、動的拡張メカニズムを実装する一部のコレクション クラスの場合HashSet
、その容量はニーズに応じて自動的に拡張されます。初期容量の設定は、コレクションのパフォーマンスとメモリ使用量に影響を与える可能性があります。コレクションのサイズが事前にわかっている場合は、適切な初期容量を設定することで、頻繁な拡張操作を回避し、パフォーマンスを向上させることができます。
負荷率 (Load Factor) は、拡張前にコレクションが達成できる充填率の割合を指します。コレクション内の要素の数が負荷率と現在の容量の積に達すると、コレクションの容量は自動的に拡張されます。デフォルトでは、Java コレクション クラスの負荷係数は通常 0.75 ですが、これは時間とスペースの消費量のバランスを取るための経験的な値です。負荷率が高くなるとスペースのオーバーヘッドが減りますが、ハッシュの衝突の可能性が高まる可能性があります。
負荷率と容量の関係は次の式容量 = 元素数量 / 负载因子
で。たとえば、初期容量が 16 で負荷係数が 0.75 のHashMap
場合、その中の要素の数が 12 (16 * 0.75) に達すると、自動拡張操作がトリガーされます。
時間と空間の間のトレードオフは、負荷率を調整することで実現できます。負荷係数が小さいと、ハッシュ衝突の可能性が低くなりますが、ストレージスペースの使用量が増加します。負荷係数を大きくすると、スペースのオーバーヘッドを減らすことができますが、ハッシュの衝突が増加し、検索と挿入のパフォーマンスに影響を与える可能性があります。
C. コレクションクラスの浅いコピーと深いコピー
コレクションクラスの浅いコピー(Shallow Copy)と深いコピー(Deep Copy)は、コレクションオブジェクトのコピー操作です。
-
浅拷贝(Shallow Copy):
- 浅いコピーとは、新しいコレクション オブジェクトを作成し、元のコレクション内の要素の参照を新しいコレクションにコピーすることを指します。
- 元のコレクションと新しいコレクションは同じ要素オブジェクトのセットを共有し、それらの間の要素参照は同じメモリ アドレスを指します。
- 元のコレクション内の要素を変更すると、新しいコレクション内の要素は同じ要素オブジェクトのセットを参照するため、それらの要素に影響します。
- 浅いコピーは、コレクション オブジェクト内の要素が不変オブジェクトであるか、要素を変更する必要がない場合に適しています。
-
ディープコピー (ディープコピー):
- ディープ コピーとは、新しいコレクション オブジェクトを作成し、元のコレクションの要素を新しいコレクションにコピーすることを指します。各要素はまったく新しいオブジェクトです。
- 元のコレクションと新しいコレクションの要素オブジェクトは独立しており、独自のメモリ アドレスを持っています。
- 元のコレクション内の要素を変更しても、新しいコレクション内の要素は異なる要素オブジェクトを参照するため、それらの要素には影響しません。
- ディープ コピーは、コレクション オブジェクト内の要素が変更可能なオブジェクトであり、要素を個別に変更または操作する必要がある場合に適しています。
コレクション クラスの浅いコピーと深いコピーは、コレクション内の要素オブジェクトではなく、コレクション オブジェクトに相対していることに注意してください。コレクション内の要素オブジェクトがコレクション オブジェクトまたはその他の参照型オブジェクトでもある場合、要素オブジェクトのコピー操作では、シャロー コピーとディープ コピーの問題も考慮する必要があります。
Java では、コレクションの浅いコピーと深いコピーは、メソッドの使用、シリアル化および逆シリアル化によるコピーなど、さまざまな方法で実装できますclone()
。具体的な実装方法は、コレクション クラスの特定の種類と要件によって異なります。コレクションのコピー操作で期待どおりの効果が得られるようにするには、特定のシナリオと要件に応じて適切なコピー方法を選択する必要があります。
D. コレクション クラスのシリアル化と逆シリアル化
コレクション クラスのシリアル化と逆シリアル化は、コレクション オブジェクトを保存または送信のためにバイト ストリームに変換し、そのバイト ストリームを元のコレクション オブジェクトに復元するプロセスを指します。Java はシリアル化および逆シリアル化メカニズムを提供し、コレクション クラスを永続化およびネットワーク間送信に便利にします。
Java では、シリアル化と逆シリアル化は次の条件を満たす必要があります。
- コレクション クラスは
java.io.Serializable
、クラスがシリアル化できることを示すマーカー インターフェイスであるインターフェイスを実装する必要があります。 - コレクション クラスのすべてのメンバー変数もシリアル化可能である必要があります。つまり、それらは基本型か実装
Serializable
インターフェイスのいずれかです。
シリアル化のプロセス (シリアル化) は、コレクション オブジェクトをバイト ストリームに変換するプロセスであり、ObjectOutputStream
クラスを使用して実装できます。具体的な手順は次のとおりです。
- シリアル化されたバイト ストリームを受信するための
FileOutputStream
orオブジェクトを作成します。ByteArrayOutputStream
- オブジェクトを作成し
ObjectOutputStream
、それを手順 1 のストリーム オブジェクトに関連付けます。 - メソッドを呼び出して
writeObject()
、コレクション オブジェクトを出力ストリームに書き込みます。つまり、シリアル化操作を実行します。 - 出力ストリームを閉じます。
逆シリアル化処理(Deserialization)は、バイトストリームを元のコレクションオブジェクトに戻す処理であり、ObjectInputStream
クラスを利用することで実現できます。具体的な手順は次のとおりです。
- バイトストリームを読み取るための
FileInputStream
orオブジェクトを作成します。ByteArrayInputStream
- オブジェクトを作成し
ObjectInputStream
、それを手順 1 のストリーム オブジェクトに関連付けます。 - 呼び出し
readObject()
メソッドは、入力ストリームからバイト ストリームを読み取り、それをコレクション オブジェクトに変換します。つまり、逆シリアル化します。 - 入力ストリームを閉じます。
サンプルコードはArrayList
例として次のとおりです。
// 序列化
List<String> list = new ArrayList<>();
list.add("Hello");
list.add("World");
try (FileOutputStream fileOut = new FileOutputStream("list.ser");
ObjectOutputStream out = new ObjectOutputStream(fileOut)) {
out.writeObject(list);
System.out.println("Serialized data is saved in list.ser");
} catch (IOException e) {
e.printStackTrace();
}
// 反序列化
try (FileInputStream fileIn = new FileInputStream("list.ser");
ObjectInputStream in = new ObjectInputStream(fileIn)) {
List<String> restoredList = (List<String>) in.readObject();
System.out.println("Deserialized data:");
for (String item : restoredList) {
System.out.println(item);
}
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
ようこそ: http://mumuxi.chat/