
89. ArrayList は LinkedList とどう違うのですか?
これは、 HashMapの内部構造に関する質問と並んで、最も人気のある質問の 1 つです。これなしでは面接は完了しません。そのため、あなたの答えはすぐに口からこぼれてしまうはずです。明らかなことに加えて(名前が異なります)、内部構造も異なります。前にArrayListとLinkedListの両方の内部構造について説明したため、実装の詳細については説明しません。ArrayList は、次の式に従ってサイズが動的に増加する内部配列を使用して実装されていること を思い出してください。<size of the current array> * 3 / 2 + 1
さらに、 LinkedList の実装では内部二重リンク リストが使用されます。つまり、リストの先頭と末尾の要素を除き、各要素は前後の要素への参照を持ちます。面接官は「 ArrayListとLinkedListのどちらが優れていますか?」というような質問をするのが好きです。あなたを捕まえることを願っています。結局のところ、どちらか一方が優れていると言うなら、それは間違った答えを出したことになります。 
-
インデックスが指定されていない場合、両方の種類のリストの末尾に新しい項目が自動的に追加されます。LinkedListでは、新しい要素が新しい末尾になります (参照のペアのみが書き換えられるため、アルゴリズムの複雑さはO(1)です)。
add メソッドは、配列内の最後の空のセル ( O(1) )に要素を追加します。
-
インデックスによって項目を追加するということは、通常、リストの中央のどこかに項目を挿入することを意味します。LinkedListでは、メソッドはまず末尾と先頭 ( O(n/2) )から要素を反復処理して目的の場所を検索し、次に、その両側の要素の参照を上書きして値を挿入します。新しい要素が挿入されます ( O(1) )。この操作の全体的なアルゴリズムの複雑さはO(n/2)になります。
同じ状況 (インデックスによる追加) では、ArrayList は目的の位置 ( O(1) ) を見つけて、右にあるすべての要素 (指定されたインデックスに既に格納されている要素を含む) を 1 つだけ右にシフトします (これは、新しい内部配列の作成とそこへの要素のコピーが必要になる場合があります) ( O(n/2) )。全体的な複雑さはO(n/2)です。
-
LinkedListの先頭に要素を追加することは、末尾に要素を追加することと似ており、新しい要素が新しい先頭 ( O(1) ) になります。ただし、ArrayList の場合、その操作ではすべての要素を右に移動する必要があります ( O(n) )。
90. ArrayList は HashSet とどう違うのですか?
ArrayListとLinkedList を操作ごとに比較して、どちらが優れているかを判断できたとしても、 ArrayListとHashSetはまったく異なるコレクションであるため、そのような比較を行うのはそれほど簡単ではありません。あるデザートを別のデザートと比較することはできますが、デザートとセイボリー料理を比較するのは困難です。それらは痛ましいほど異なります。それでも、それらの違いをいくつか指摘してみます。-
ArrayList はListインターフェイスを実装し、 HashSet はSetインターフェイスを実装します。
-
ArrayListでは、インデックスによって要素にアクセスできます。get操作のアルゴリズムの複雑さはO(1)ですが、HashSet では反復によってのみ目的の要素にアクセスできるため、アルゴリズムの複雑さはO(1)からO(n) の範囲になります。
-
ArrayList では要素の重複が許可されます。HashSetでは、すべての要素が一意です。HashSet にすでに存在する要素を追加しようとすると失敗します (重複はハッシュコードによってチェックされるため、このコレクションの名前が付けられています) 。
-
ArrayList は内部配列を使用して実装されますが、HashSetは内部HashMapを使用して実装されます。
-
ArrayList は要素の挿入順序を維持しますが、HashSetは順序なしのセットであり、要素の順序は維持しません。
-
ArrayList では任意の数の null 値を許可しますが、 HashSetに追加できるのは 1 つの null 値のみです(結局、要素は一意である必要があります)。
91. Java にはなぜこれほど多くの異なる動的配列実装があるのですか?
これはむしろ哲学的な質問です。また、なぜ彼らはこれほど多くの新しくて多様なテクノロジーを思いつくのかと尋ねることもできます。便宜上。そして、同じことが多数の動的配列実装にも当てはまります。どれも最良または理想的な実装とは言えません。それぞれに特定の状況に応じた利点があります。私たちの仕事は、それぞれの違いと長所/短所を理解し、特定の状況に最適なコレクションを使用できるようにすることです。92. Java にはなぜこれほど多くの異なるキーと値のストレージ実装があるのですか?
ここでの状況は、動的配列実装の場合と同じです。他より普遍的に優れているものは絶対にありません。それぞれに長所と短所があります。そしてもちろん、私たちは彼らの強みを最大限に活用しなければなりません。 例:多数のマルチスレッド クラスを含む並行パッケージには、独自の並行コレクションがあります。ConcurrentHashMapクラスは、マルチスレッド環境でデータを操作する場合の安全性の点で標準の HashMap よりも優れていますが、その代償としてパフォーマンスが低下します。そして、どのような状況においても最善の選択ではない実装は、徐々に使用されなくなります。 例: Hashtableは、もともとスレッドセーフなHashMapであることを意図していましたが、マルチスレッド環境で作業する場合には ConcurrentHashMap の方がHashtableよりも優れているため、忘れられ、使用されなくなりました。93. 要素のコレクションを並べ替えるにはどうすればよいですか?
まず最初に言っておきたいのは、コレクション要素を表すクラスは、compareToメソッドで構成されるComparableインターフェイスを実装する必要があるということです。または、 Comparatorインターフェイス ( compareメソッドを含む)を実装するクラスが必要です。どちらのメソッドも、特定のタイプのオブジェクトを比較する方法を示します。並べ替えアルゴリズムは要素を比較するためにどのような原理を使用するかを理解する必要があるため、これは並べ替えの際に重要です。これは主に、並べ替えるクラスにComparable を直接実装することによって行われます。Comparator を使用することはあまり一般的ではありません。あるライブラリのクラスを使用していて、そのクラスがComparableを実装していないが、そのオブジェクトのコレクションをソートする必要があるとします。このクラスのコードは (拡張する場合を除いて) 変更できないため、クラスのオブジェクトを比較する方法を示すComparatorの実装を作成できます。そしてもう一つの例。同じ型のオブジェクトをさまざまな方法で並べ替える必要がある場合は、さまざまな状況で使用する複数のComparator実装を作成できます。原則として、多くのすぐに使用できるクラス ( Stringなど) はすでにComparableインターフェースを実装しています。つまり、これらのクラスを比較する方法について心配する必要はありません。そのまま使用してください。 最初の最も明白な方法は、 TreeSet クラスまたはTreeMapクラスを使用することです。これらのクラスは、クラス要素によって実装されたコンパレータに基づいて並べ替えられた順序で要素を格納します。TreeMap は値ではなくキーを並べ替えることを忘れないでください。Comparableの代わりにComparator を使用する場合は、コレクションの作成時に Comparatorオブジェクトをコレクションのコンストラクターに渡す必要があります。TreeSet treeSet = new TreeSet(customComparator);
しかし、別の種類のコレクションがある場合はどうなるでしょうか? どうやって並べ替えるのですか?この場合、Collectionsユーティリティ クラスの2 番目の方法であるsort()メソッドが適しています。このメソッドは静的であるため、クラスの名前を先頭に追加し、並べ替えるリストを渡すだけで済みます。例えば:
Collections.sort(someList);
ComparableではなくComparator の実装を使用している場合は、それを 2 番目の引数として渡す必要があります。
Collections.sort(someList, customComparator);
この操作により、渡されたリスト内の要素の内部順序が変更されます。リストはコンパレータを使用して並べ替えられます。渡されるリストは変更可能である必要があることに注意してください。変更可能でない場合、メソッドは失敗し、 UnsupportedOperationException をスローします。3番目のオプションは、コレクションの要素を並べ替えるStreamクラスのsortedメソッドを使用することです。Comparable を使用している場合:
someList = someList.stream().sorted().collect(Collectors.toList());
Comparator を 使用している場合:
someList = someList.stream().sorted(customComparator).collect(Collectors.toList());
4番目の方法は、バブル ソート
やマージ ソートなど
のソート アルゴリズムを手動で実装することです。
オブジェクトクラス。equals() と hashCode()
94. Java の Object クラスについて簡単に説明してください。
レビューの2 番目の部分 では、 Objectクラスのメソッドについてすでに説明しました。ここで、 Objectクラスが Java のすべてのクラスの祖先であることを思い出してください。これには 11 のメソッドがあり、それらはすべてのクラスによって継承されます。
95. Java では、equals() と hashCode() は何に使用されますか?
hashCode() は、すべてのクラスに継承されるObjectクラスのメソッドです。その仕事は、特定のオブジェクトを表す数値を生成することです。このメソッドの動作例はHashMapにあります。このメソッドはキー オブジェクトに対して呼び出され、ローカル ハッシュコードを取得します。これにより、キーと値のペアがどのバケット (内部配列のセル) に格納されるかが決まります。このメソッドは通常、オブジェクトを識別する主な方法の 1 つとして、 equals()メソッドで使用されます。equals()は、オブジェクトを比較し、それらが等しいかどうかを判断するObjectクラスのメソッドです。標準の==比較演算子はオブジェクト参照のみを比較するため、オブジェクトには適していないため、 このメソッドはオブジェクトを比較する必要があるあらゆる場所で使用されます。96. Javaにおけるequals()とhashCode()の間の契約について教えてください。
まず、 equals()メソッドとhashCode()メソッドが正しく動作するには、それらを正しくオーバーライドする必要があると言わせてください。新しい実装は次のルールに従う必要があります。- 等号がtrue を返す同一のオブジェクトは、同じハッシュ コードを持つ必要があります。
- 同じハッシュ コードを持つオブジェクトは必ずしも等しいとは限りません。
GO TO FULL VERSION