面接官は配列とArrayListにどう答えますか?


誰もが面接で集合に関する質問をされると思いますが、多くの人が答えるときにそんなに論理的ではなく、どこでどこまで話しているのか、この文章は集合に関する質問を大体撫でています.各プログラミング言語には、ループ、配列、フロー制御文があり、配列は線形テーブルデータ構造であり、メモリ空間は連続しており、保存されたデータ型も一致しています.
この2点こそ、配列のランダムアクセスが非常に効率的であり、同時に両刃の剣でもあり、配列の他の操作効率が低くなります.例えば、増加、削除は、配列内のデータの連続性を維持するために、大量の消費性能のデータ移行操作を行います.
配列というタイプに対してjavaにはコンテナクラスがあり、例えばArrayList、ArrayListは配列のパッケージであり、下位層では配列で実現されている.配列は定義時に指定された長さでなければならないため、定義後は長さを増やすことができない.つまり、元の配列に1段接続することは不可能であるため、ArrayListはこの問題を解決した.配列容量を超えると、ArrayListは拡張され、拡張後の容量は前の1.5倍になり、前の配列のデータをコピーします.
次に、ArrayListのソースコードを見てみましょう.
 private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

ソースコードの配列の最大容量はInteger.MAX_VALUE-8、なぜ8を引くのか、これは上の定義の上の注釈です.
 /**
     * The maximum size of array to allocate.
     * Some VMs reserve some header words in an array.
     * Attempts to allocate larger arrays may result in
     * OutOfMemoryError: Requested array size exceeds VM limit
     */

まず、いくつかのVMが配列に保存したヘッダ情報です.より大きな配列を割り当ててみると、OutOfMemoryErrorが発生し、要求された配列のサイズがVMの制限を超えてしまう可能性があります.
このコードを見ていると、頭の中に2つの大きな疑問符が現れましたか??まず、なぜこの配列属性をtransientで修飾する必要があるのか考えましたか?△このキーワードが何をしているのか知りたいなら、私の前の文章を見てください.面接でjavaのシーケンス化はどう答えますか.
transient Object[] elementData; // non-private to simplify nested class access

面接の時、あなたはどう答えますか?
ArrayListは動的配列に基づいて実現されるため,すべての空間が使用されるわけではない.したがってtransient修飾を用いることで,自動シーケンス化を防止できる.
したがってArrayListはシーケンス化と逆シーケンス化をカスタマイズし,具体的にはwriteObjectとreadObjectの2つの方法を見ることができる.
オブジェクトにwriteObjectメソッドとreadObjectメソッドがカスタマイズされている場合、JVMはこの2つのカスタムメソッドを呼び出してシーケンス化と逆シーケンス化を実現します.
2つ目の質問:この属性のタイプはなぜ汎用ではなくObjectなのか.
ここで皆さんにお話しします.
JAvaでの汎用運用の目的はオブジェクトの再利用であり、同じ方法であり、複数のオブジェクトタイプをサポートすることができる.Objectと汎用は作成時には大きな違いはないが、JVMにはTという概念はなく、Tは作成時にのみ存在し、仮想マシンに移行する際には、仮想機会がこの汎用フラグを消去する.つまり、Tを指定したタイプに置き換えると、指定したタイプがなければ、Objectで置き換えられます.また、Objectはnew Object()で、つまりインスタンス化できますが、Tはインスタンス化できません.反射の面では,実行時からTのインスタンスを返す場合,強制変換を必要とせず,Objectは変換を必要とする.
ArrayListに要素を追加しようとすると、javaは自動的にチェックして、集合に新しい要素を追加する容量があることを確認します.もしなければ、自動的に拡張します.以下はコアコードです.私はすでにコードに注釈を追加して、みんなの理解を助けることができます.
private void ensureExplicitCapacity(int minCapacity) {
    modCount++;
    // overflow-conscious code
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}

上のコードに変数modCount++がありますが、ここを見たときは確かに疑問に思っていましたが、この変数はAbstractListで定義されたprotected修飾のグローバル変数で、この変数は構造的な変化の回数を記録したもので、構造的な変化はリストサイズを変更する操作です.ArrayListはスレッドが安全ではないクラスで、この変数はマルチスレッド環境で反復器を使用することを保証するために使用され、同時に集合を修正し、同じ時点で1つのスレッドしか集合を修正できず、1つ以上あればConcurrentModficationExceptionを放出します.
private void grow(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = elementData.length;
    //       :       ,
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    if (newCapacity - minCapacity < 0)  //                   ,    
        newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > 0) //           ,         ,       
        newCapacity = hugeCapacity(minCapacity);
    // minCapacity is usually close to size, so this is a win:
    //   ,     d           
    elementData = Arrays.copyOf(elementData, newCapacity);
}

    private static int hugeCapacity(int minCapacity) {
    if (minCapacity < 0) // overflow
        throw new OutOfMemoryError();
        //  Integer-8         ,   Integer    
    return (minCapacity > MAX_ARRAY_SIZE) ?
        Integer.MAX_VALUE :
        MAX_ARRAY_SIZE;
}

次に、指定した場所に要素を追加する方法を見てみましょう.
public void add(int index, E element) {
    rangeCheckForAdd(index);
    //    
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    System.arraycopy(elementData, index, elementData, index + 1,
                     size - index);
    elementData[index] = element;
    size++;
}

1つの集合が十分大きい場合、add操作は配列の末尾に要素を追加する効率が非常に高いが、指定された位置に要素を追加する場合も、System.arraycopy()という大量の移動レプリケーション操作が必要であることがわかる.
ここまで、ArrayListの最大のメリットは何ですか?私たちが普段の開発でコンテナに触れたとき、なぜリストファミリーのメンバーを選択し、配列を直接選択しないのでしょうか.自分がコードを叩いたことを思い出すと、答えが出てきました.
ArrayListは大部分の配列の操作方法をカプセル化しています.例えば、データの挿入、削除、移動など、集合内部で手伝ってあげました.また、動的拡張をサポートしています.これは配列とは比べものになりません.
ここで注意しなければならないのは、集合の定義を開始するときに、私たちがどれだけの集合が必要かを知っていれば、集合の内部でデータの移動を行い、複製も非常に時間がかかるため、最初から集合のサイズを指定する必要があります.
では配列はいつ使われますか?1、java ArrayListは基本タイプを格納できません.int,long、保存する場合はInteger,Longにカプセル化する必要がありますが、自動的にボックスを外したり、性能の消耗もあるので、基本タイプを保存したり、性能に特に注目したりすれば、配列を使用することができます.2、データの数の大きさが既知であれば、操作も非常に簡単であり、ArrayListのほとんどの方法を必要とせず、配列を直接使用することもできる.
もし本文に異議があれば、私の友达を追加することができます(問題があれば、みんなが私の友达を追加することを歓迎します)、下の伝言区で伝言を残してもいいです.私はすぐに修正します.この文章が面接の途中で波を破るのに役立つことを望んでいます.
このような分かち合いは私はずっと続いて、あなたの関心、転送と美しさは私の最大の支持に対して、感謝します.私に注目して、私たちは一緒に成長します.