5.ソースコードインタビューの質問コレクションを一覧表示する

1.新しいArrayListを作成し、値を追加します。この時点での配列のサイズはどれくらいですか?次の拡張前に利用可能な最大サイズはいくつですか?
回答:ここでの配列のサイズは1で、次の拡張前に使用可能な最大サイズは10です。ArrayListパラメーターなしコンストラクターが初期化されるとき、デフォルトのサイズは空の配列であるためです。要素を初めて追加するとき、要素は展開され、サイズはデフォルトの10です。

2. ArrayListに値を継続的に追加する場合、11番目の配列に達したときの配列のサイズはどれくらいですか?
回答:現時点でのアレイのサイズは15です。ここで検討しているのは拡張式です。11番目の要素を増やすと、配列のサイズは11になると予想されますが、実際には配列の最大容量は10です。このとき、拡張が必要です。拡張式はoldCapacity +(oldCapacity >> 1)、oldCapacityは配列の現在のサイズを表し、現在のシナリオ計算式は10 + 10/2 = 15であり、11が需要を満たすことがわかったため、配列のサイズは15に拡張されます。

3.配列が初期化されて値が追加された後、addAllメソッドを使用して一度に15個の値を追加する場合、最終的な配列のサイズはどれくらいですか?
回答:最終的な配列のサイズは16です。最初の質問では、配列に値を追加した後、実際のサイズは1で、使用可能な最大サイズは10であると計算されています。次に、一度に15個の値を追加する必要があります。配列の予想サイズは16であり、配列の使用可能な最大サイズはわずか10です。 、明らかに十分ではありません。拡張する必要があります。拡張サイズは10 + 10/2 = 15です。現時点では、拡張サイズはまだ期待値の16未満であることがわかります。このとき、ソースコードで次の戦略が採用されます。

//newCapacity本次扩容的大小,minCapacity期望的数组最小大小
//如果扩容后的值 < 期望值,期望值就等于本次扩容的大小
if (newCapacity - minCapacity < 0)
    newCapacity = minCapacity;

したがって、拡張後のアレイの最終的なサイズは16です。

4.コピーする必要のある非常に大きな配列があります。元の配列サイズは5kです。すばやくコピーするにはどうすればよいですか?
回答:新しい配列を作成するときは、新しい配列のサイズを5kとして指定してください。元の配列は比較的大きいため、新しい配列を作成するときに配列のサイズを指定しないと、頻繁に拡張されます。頻繁に拡張すると、コピー作業が多くなり、パフォーマンスのオーバーヘッドが増加します。

5.拡張によってパフォーマンスが低下するのはなぜですか?
回答:展開するとき、最下層はSystem.arraycopyメソッドを使用します。このメソッドは、元の配列のすべてのデータを新しい配列にコピーするため、パフォーマンスの消費はより深刻になります。

6. ArrayListがあり、データは2、3、3、3、4です。for(int i = 0; i <list.size(); i ++)まで、値3の要素を削除してください。きれいですか?削除がクリーンでない場合、最終的な削除の結果はどうなりますか、またその理由は何ですか?

public static void main(String[] args) throws Exception {
    
    
	List<String> list = new ArrayList<String>() {
    
    {
    
    
	    add("2");
	    add("3");
	    add("3");
	    add("3");
	    add("4");
	}};
	for (int i = 0; i < list.size(); i++) {
    
    
	    if (list.get(i).equals("3")) {
    
    
	        list.remove(i);
	    }
	}
}

回答:きれいに削除することはできません。削除の最終結果は2、3、4であり、3は削除できません。その理由を下図に示します。要素が削除されるたびに、要素の背後にある要素が前方に移動し、ループiが増加します。したがって、最初の3つを削除した後、次の3つは失われ、削除に失敗します。
ここに写真の説明を挿入

7. forを拡張することで、6の問題を削除できますか?
回答:いいえ、ConcurrentModificationExceptionが報告されます。拡張forがループ内にある場合、イテレーターのnext()メソッドが呼び出されます。remove()メソッドが呼び出されて削除されると、modCountの値は+1になりますが、イテレーターのexpectedModCountの値はこの時点では変更されていません。次回イテレーターがnext()メソッドを実行すると、expectedModCount!= modCountはConcurrentModificationExceptionを報告します。

8. Iterator.remove()メソッドを使用して6の問題を削除できますか?
回答:はい。Iterator.remove()メソッドは、実行中に最新のmodCountをexpectedModCountに割り当てるため、次のループでは、modCountとexpectedModCountが等しくなります。

9. ArrayListとLinkedListの違いは何ですか?
回答:最大の違いは、2つの基になるデータ構造が異なることです。ArrayListの最下層は配列であり、LinkedListの最下層は二重リンクリストです。2つのデータ構造の違いは、操作APIの実装の違いにもつながります。新しい実装を例にとると、ArrayListは最初に拡張するかどうかを計算して決定し、次に新しく追加されたデータを配列に直接割り当てますが、LinkedListは、挿入されたノードとその前後のノードの間のポイント関係のみを変更します。次に、アプリケーションのシナリオが異なります。ArrayListは一致するシナリオをすばやく見つけるのに適していますが、LinkedListは頻繁に追加または削除されるシナリオに適しています。

10. ArrayListとLinkedListの最大容量はありますか?
回答:ArrayListには最大容量があります。最大容量はIntegerの最大値です。JVMはこの値を超える配列にメモリスペースを割り当てません。LinkedListの最下層は二重にリンクされたリストであり、理論的には無限になります。ただし、ソースコードでは、LinkedListの実際のサイズはint型を使用します。これは、LinkedListがIntegerの最大値を超えることはできないことも示しています。超えない場合、オーバーフローします。

11. ArrayListとLinkedListはnull値をどのように処理しますか?
回答:ArrayListを使用すると、null値を追加したりnull値を削除したりできます。null値を削除する場合、最初から開始し、最初の値がnullである要素を削除します。LinkedListが追加または削除されると、null値の特別なチェックは行われず、追加および削除も許可されます。

12. ArrayListとLinedListはスレッドセーフですか?その理由は何ですか?
回答:2つを非共有変数として使用する場合、たとえば、メソッドでローカル変数としてのみ使用する場合、スレッドの安全性の問題はありません.2つが共有変数の場合のみ、スレッドの安全性の問題が発生します。主な問題は、マルチスレッド環境では、すべてのスレッドがいつでも配列とリンクされたリストを操作できることです。これにより、値が上書きされ、さらには無秩序になる可能性があります。スレッドの安全性に問題がある場合、反復プロセス中にConcurrentModificationExceptionが頻繁に報告されます。これは、現在のループ中に配列またはリンクリストの構造が他のスレッドによって変更されたことを意味します。

13. ArrayListとLinedListのスレッドの安全性の問題を解決するにはどうすればよいですか?
回答:Javaソースコードでは、コレクションのsynchronizedListメソッドを使用して問題を解決することをお勧めします。synchronizedListの戻り値は、すべてのメソッドに同期ロックが追加されたリストであり、配列とリンクリストを同時に1つのスレッドでのみ変更できるようにするか、CopyOnWriteArrayListを使用して解決してください。このクラスについては後で詳しく説明します。

14.二重にリンクされたリストについて説明してください。
回答:二重にリンクされたリストの双方向は、フロントノードとバックノードの間に参照があり、リンクされたリストのノードはノードと呼ばれることを意味します。ノードには、前のノード、それ自体のノード、次のノードの3つの属性グループがあります。ノードAとBが隣接しているとすると、ノードAの次のノードはB、ノードBの前のノードはAであり、2つは相互に参照します。リンクリストのヘッドノードはヘッドノードと呼ばれ、ヘッドノードの前のノードはnull、テールはテールノードと呼ばれ、テールノードの次のノードはnullです。リンクリストデータが空の場合、ヘッドノードとテールノードは同じノードです。それ自体の値はnullであり、前後のノードを指す値もnullです。

15.二重にリンクされたリストの追加と削除について説明してください。
回答:追加するときは、リンクリストの先頭から追加するか、リンクリストの末尾から追加するかを選択できます。リンクリストの末尾から追加する場合は、現在のノードをテールノードに直接追加すると、ノードが自動的にテールノードになります。削除するときは、削除したノードの次のノードの前のノードを前のノードにポイントし、削除したノードの前のノードの次のノードを次のノードにポイントし、最後に削除したノードをnullに設定します。

おすすめ

転載: blog.csdn.net/Jgx1214/article/details/109064324