ホームページ  >  記事  >  Java  >  Java の ArrayList の初期容量が 10 である理由は何ですか?

Java の ArrayList の初期容量が 10 である理由は何ですか?

WBOY
WBOY転載
2023-05-10 14:19:131484ブラウズ

HashMap の初期容量が 16 なのはなぜですか?

ArrayList の初期化能力について話すときは、まず HashMap の初期化能力を確認する必要があります。 Java 8 のソース コードを例として示します。HashMap には、初期化容量と読み込み係数の 2 つの関連要素があります。

/**
 * The default initial capacity - MUST be a power of two.
 */
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
/**
 * The load factor used when none specified in constructor.
 */
static final float DEFAULT_LOAD_FACTOR = 0.75f;

HashMap では、配列のデフォルトの初期化容量は 16 です。データがいっぱいになると、デフォルト容量の0.75までの場合、2倍に拡張されます。もちろん、ユーザーは初期化中に指定されたサイズを渡すこともできます。ただし、2 の n 乗の値を使用するのが最適であることに注意してください。2 の n 乗に設定されていない場合、HashMap も変換しますが、もう 1 つの手順が必要になります。

HashMap の実装原理については、インターネット上にすでにたくさんの記事があるため、ここでは詳しく説明しません。知っておく必要があることの 1 つは、キー値の座標を計算する HashMap のアルゴリズムです。つまり、キー値をハッシュして配列内の座標にマッピングします。

このとき、HashMapの容量を2のn乗にすることで、ハッシュ演算時に10進数に変換せずにビット演算でメモリを直接操作できるため効率が高くなります。

一般に、HashMap が 2 の n 乗を使用し、デフォルト値が 16 である理由は、 以下の考慮事項があると考えられます。 ハッシュの衝突を減らす;

  • マップ クエリの効率を向上させる;

  • ##割り当てが小さすぎるため、頻繁な拡張を防ぐ;
  • 過剰な割り当てはリソースを無駄にします;
  • つまり、HashMap がデフォルト値として 16 を使用する理由は、ハッシュの衝突を減らし、効率を向上させるためです。
  • ArrayList の初期容量は 10 ですか?

  • 次に、ArrayList の初期容量が 10 であるかどうかを確認し、なぜこの値になるのかを説明します。

まず、Java 8 の ArrayList 初期化容量のソース コードを見てみましょう:

/**
 * Default initial capacity.
 */
private static final int DEFAULT_CAPACITY = 10;

明らかに、デフォルトのコンテナ初期化値は 10 です。また、JDK1.2 から JDK1.6 まで、この値は常に 10 です。

JDK1.7 以降、ArrayList を初期化するとき、デフォルト値は空の配列に初期化されます。

    /**
     * Shared empty array instance used for default sized empty instances. We
     * distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
     * first element is added.
     */
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
    
    /**
     * Constructs an empty list with an initial capacity of ten.
     */
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

ここにはデフォルト値が正しいという友人がいるはずです。 Java 8 の ArrayList の初期サイズは 10 ではなく 0 です。また、コンストラクター メソッドのコメントにも奇妙な点があることがわかります。初期容量 10 の空のリストを構築します。なんてこった?明らかに空いてますよ!

疑問は捨てて、まず ArrayList の add メソッドを見てみましょう:

    public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }

ansureCapacityInternal メソッドが add メソッドで呼び出されます。このメソッドを入力すると、最初は空のコンテナーであるため、

size=0

Incoming minCapacity=1:

    private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }

上記のメソッドでは、まず、calculateCapacity によって容量が計算されます。 <pre class="brush:java;"> private static int calculateCapacity(Object[] elementData, int minCapacity) { if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { return Math.max(DEFAULT_CAPACITY, minCapacity); } return minCapacity; }</pre> は、minCapacity が 10 (

DEFAULT_CAPACITY=10

) に再割り当てされていることを検出し、

ensureExplicitCapacity(minCapacity);

ThisminCapacity を渡します。 =10,以下はメソッド本体です: <pre class="brush:java;"> private void ensureExplicitCapacity(int minCapacity) { modCount++; // overflow-conscious code if (minCapacity - elementData.length &gt; 0) grow(minCapacity); } private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; int newCapacity = oldCapacity + (oldCapacity &gt;&gt; 1); if (newCapacity - minCapacity &lt; 0) newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE &gt; 0) newCapacity = hugeCapacity(minCapacity); // minCapacity is usually close to size, so this is a win: elementData = Arrays.copyOf(elementData, newCapacity); }</pre>上記のコードのgrowメソッドは拡張を処理するために使用され、容量を1.5に拡張します。元のサイズの 2 倍になります。

上記の処理フローを理解すると、ArrayList の初期容量は基本的に 10 のままですが、遅延ロードが使用されているだけであることがわかります。これは、メモリを節約するために Java 8 によって実行される最適化です。したがって、最初から最後まで、ArrayList の初期容量は 10 です。 遅延読み込みの利点をもう 1 つ挙げておきます。プログラム内に数千の ArrayList がある場合、デフォルト サイズの 10 オブジェクトは、作成時に基になる配列に 10 個のポインタ (40 または 80) が割り当てられることを意味します。バイト) を作成し、それらを null 値で埋めると、(null 値で埋められた) 空の配列は多くのメモリを占有します。配列を遅延初期化できれば、メモリ領域を大幅に節約できます。 Java 8 での変更は上記の目的のためです。

ArrayList の初期容量が 10 なのはなぜですか?

最後に、ArrayList の初期容量が 10 である理由について説明します。実際、理由はなく、大きすぎず、小さすぎず、目にちょうど良い「感じ」であると言えます。

まず、HashMap について説明するときに、HashMap が 2 の n 乗を選択する理由は、ハッシュ アルゴリズムのパフォーマンスと衝突を考慮するためであると述べました。この問題は ArrayList には存在しません。 ArrayList は、アルゴリズム レベルでの最適化を考慮せず、単純に拡張する配列です。一定の値を超えると成長する可能性があります。したがって、理論的に言えば、ArrayList の容量は任意の正の値にすることができます。

ArrayList のドキュメントには、10 が選択された理由が説明されていませんが、おそらくパフォーマンスの損失とスペースの損失の間の最適な一致を考慮したためだと思われます。 10. 大きすぎず、小さすぎず、メモリスペースを無駄にせず、パフォーマンスもそれほど低下させません。

そもそもなぜ 10 が選ばれたのかを尋ねる必要がある場合は、このコードの作成者「Josh Bloch」に尋ねる必要があるかもしれません。

注意深く観察すると、他にもいくつかの興味深い初期化容量の数値が見つかるでしょう:

ArrayList-10
Vector-10
HashSet-16
HashMap-16
HashTable-11

ArrayList の初期化容量は Vector の初期化容量と同じです。 10; HashSet と HashMap の初期化容量は同じで 16; HashTable は 11 だけを使用しますが、これも非常に興味深い質問です。

以上がJava の ArrayList の初期容量が 10 である理由は何ですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はyisu.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。