インタビューの分析の中で最も頻繁に寄せられる質問のJavaコレクション・フレームワーク

話リストの設定差,, 3の地図?

  • (良いヘルパーに対処するために)リスト:  リストはインターフェースの集合が一意でない記憶する(複数の要素が同じオブジェクトを参照存在し得る)、オブジェクトを注文
  • セット(ユニークな自然に注意を払う):  重複したコレクションを許可していません。これ以上の要素が同じオブジェクトを参照があるでしょう。
  • 地図(検索するキーを持つ専門家):  使用するキーと値のペアを格納します。地図を維持し、キーに関連付けられた値になります。キーを2は、同じオブジェクトを参照することができ、典型的にはタイプStringキーの、キーを繰り返すことはできないが、任意のオブジェクトであってもよいです。

ArrayListのとLinkedListの違いは?

  • 1.保証スレッドセーフです ArrayList  と、  LinkedList スレッドセーフであることが保証されていないこと、同期されません。

  • 2.基礎となるデータ構造 Arraylist  用いたボトム層  Object アレイをLinkedList 使用して底  二重リンクリスト  データ構造を(JDK1.6円形のリンクリストの前に、JDK1.7がキャンセル円形二重連結リスト双方向注目区別円形のリンクリストとして、以下に説明します。 !)

  • 影響を受けた場所であれば3を挿入及び削除の要素:  ①  ArrayList 時間インサートと複合要素の削除要素は、被写体の位置に影響を与えるので、ストレージのアレイを使用。 たとえば、次の実装add(E e) 方法の場合は、  ArrayList このリストに追加指定された要素の終わりに、デフォルトで、この場合、時間複雑度は、O(1)です。私は(そして、指定された場所に要素を挿入し、削除したい場合でも、add(int index, E element) 時間の複雑さに)O(NI)です。i番目の要素の後の最初のセットで上記動作を行うときので、私は(NI)の要素は、後方/前方方向ビット操作を実行しなければなりません。②  LinkedList ので、リストメモリをリンクされadd(�E e)、あなたがの場所を指定したい場合は、約O(1)、要素位置からの影響の要素の時間複雑度を削除、挿入する方法iの単語(の要素の挿入や削除(add(int index, E element)概算)時間の複雑さをo(n))理由に必要性特定の場所に、次に挿入されます。

  • 4.サポート高速ランダムアクセス: LinkedList  効率的なランダム要素へのアクセス、およびサポートしていない  ArrayList サポートを。オブジェクト要素が(に対応する要素番号を介して、高速ランダムアクセスへの迅速なアクセスがあるget(int index) 方法)。

  • 5.メモリフットプリント:  無駄のArrayListは、主に、リストの最後にリストに反映されている空間は、いくつかの空き容量、コストおよびスペースLinkedListのは、その要素のそれぞれに反映される予約されますので(ArrayListのより多くのスペースを消費する必要があります直接的かつ即時の前任者と後継者のデータを格納します)。

 

補足:ランダム・インタフェース

public interface RandomAccess {
}

ソースを表示私たちは、その実際に見つかった  RandomAccess インターフェース何も定義されていません。だから、私の意見では  RandomAccess インタフェースはちょうどロゴのベールです。どのようなアイデンティティ?ロゴは、ランダムアクセス機能を備えたこのインタフェースを実装しています。

binarySearch()方法は、受信リストかどうかを決定することである  RamdomAccess その場合、呼び出し、インスタンスindexedBinarySearch()メソッドを、そうでない場合、その呼iteratorBinarySearch()方法

    public static <T>
    int binarySearch(List<? extends Comparable<? super T>> list, T key) {
        if (list instanceof RandomAccess || list.size()<BINARYSEARCH_THRESHOLD)
            return Collections.indexedBinarySearch(list, key);
        else
            return Collections.iteratorBinarySearch(list, key);
    }

ArrayList 実装  RandomAccess インタフェースが、  LinkedList 無実装。なぜ?私はそれが構造や基礎データに関連していると思います!ArrayList 底部層は、アレイであって、  LinkedList 底部がリンクされたリストです。自然のサポートランダムアクセスの配列は、時間の複雑さは非常に高速ランダムアクセスと呼ばれる、O(1)です。特定の場所の要素にアクセスするために特定の場所にリストをトラバースする必要がある、時間複雑度はO(N)であり、これは、高速ランダムアクセスをサポートしていません。ArrayList 実装  RandomAccess 彼の高速なランダムアクセスによって示されるように、インターフェイスを。 RandomAccess 単純にそれを言っていない、インターフェイスを識別し  ArrayList 実現する  RandomAccess 高速ランダムアクセス機能を持つインタフェースを!

ここでは、リスト・トラバーサルモードの選択を要約したものです。

  • 実装の  RandomAccess 一般的な循環のためのリストインターフェースの好み、続きのforeach、
  • 未実現  RandomAccessインターフェイスリスト、優先イテレータトラバーサルデータの、大きいサイズ(反復子が実装されて下にあるスルー横断するforeachの)は、ループの通常使用していません

補足:双方向と双方向リンクリスト循環リスト

二重にリンクされたリスト:  二つのポインタ、前のポイント前のノード、次の後続ノードへのポインタを含みます。

双方向循環リスト:  ヘッド次最後のノード点、及び最後のノードの前にヘッド点は、環を形成します。

uploading.4e448015.gif

ベクターおよびArrayListのそれ?なぜArrayListの間の差は、Vectorそれを置き換えますか?

 

Vectorクラスのすべてのメソッドは同期化されています。Vectorオブジェクトは、同期操作に多くの時間を過ごすためにベクトルのコードワードにアクセスするために安全に二つのスレッドが、一つのスレッドによってアクセスすることができます。

Arraylist同期していない、スレッドのArrayListの安全な使用を確保するために必要でないときことをお勧めします。

HashMapのとHashtableの違い

  1. スレッドに、それは安全である:  HashMapのは、スレッドセーフではありません、ハッシュテーブルは、スレッドセーフであり、内部ハッシュテーブルの基本的な方法がされているsynchronized 修正します。(あなたがスレッドセーフを確保したい場合は、ConcurrentHashMapのそれを使用!)。
  2. 効率性:  スレッドの安全性の問題ので、HashMapのハッシュテーブルの効率よりも少し高いです。さらに、ハッシュテーブルは、基本的に排除され、それは、コードで使用されていません。
  3. NULL値とヌルキーのサポート:  ハッシュマップで、ヌルキー、唯一のそのようなキーとして、ヌルの値に対応する1つまたは複数のキーがあってもよいです。しかし限り、ヌル、直接スローにNullPointerExceptionがあるので、キーにハッシュテーブルを置きます。
  4. 初期容量と各容量拡大サイズの異なるサイズ:  ①容量が指定されていない場合の初期値を作成し、ハッシュテーブルデフォルトの初期サイズは、各拡張後、元の容量が2N + 1となり、11です。HashMapのデフォルトの初期サイズは16です。各拡張後、容量が2倍になります。初期値の容量が与えられた場合に作成②場合は、ハッシュテーブルを使用すると、指定されたサイズを使用するように指示します、とHashMapのは、そのサイズが2のべき乗で拡大していきます(中HashMapのtableSizeFor()アプローチの保証、ソースコードは以下の通りです)。HashMapのは、常にハッシュテーブルのサイズとして2の電源を使用すること、それは2の累乗である理由に、後に導入されます。
  5. :データ構造の基礎となる  ハッシュマップは、検索時間を短縮する赤黒木リストに、(デフォルトは8である)の鎖長が閾値よりも大きい場合、ハッシュ衝突を解決する際に大幅な変更を行った後にJDK1.8を。ハッシュテーブルにはそのようなメカニズムではありません。

HashMapのコンストラクタの初期容量を持ちます:

    public HashMap(int initialCapacity, float loadFactor) {
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal initial capacity: " +
                                               initialCapacity);
        if (initialCapacity > MAXIMUM_CAPACITY)
            initialCapacity = MAXIMUM_CAPACITY;
        if (loadFactor <= 0 || Float.isNaN(loadFactor))
            throw new IllegalArgumentException("Illegal load factor: " +
                                               loadFactor);
        this.loadFactor = loadFactor;
        this.threshold = tableSizeFor(initialCapacity);
    }
     public HashMap(int initialCapacity) {
        this(initialCapacity, DEFAULT_LOAD_FACTOR);
    }

以下のHashMapは常にハッシュ・テーブルのサイズとして2の電源を使用することをこれは、メソッドを確実にします。

    /**
     * Returns a power of two size for the given target capacity.
     */
    static final int tableSizeFor(int cap) {
        int n = cap - 1;
        n |= n >>> 1;
        n |= n >>> 2;
        n |= n >>> 4;
        n |= n >>> 8;
        n |= n >>> 16;
        return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
    }

HashMapのとHashSetの違い

あなたが見れば  HashSet ソースコードを、あなたは知っている必要があります。HashSetのは、基礎となるのHashMapの実装に基づいています。(HashSetの源は、非常に小さい、加えているので  clone() writeObject()readObject()自身が実装する必要がHashSetの外で、他の方法があるのHashMapのメソッドを直接呼び出します。

HashMapの HashSetの
実装Mapインタフェース 実装Setインタフェース
ストアのキーと値のペア 唯一のストレージオブジェクト
するために呼び出す  put()マップに要素を追加 コール  add()セットに要素を追加する方法を
使用HashMapのキー(鍵)算出されたハッシュコードであります HashSetの部材は、ハッシュコード値を計算するオブジェクト、ハッシュコードは、2つのオブジェクトのために同じであってもよく、それは決意対象等価()メソッドに等しく、

重複HashSetのかどうかを確認する方法

あなたがオブジェクトに参加するとHashSetHashSetのは、最初のオブジェクトの計算されます、hashcode追加したオブジェクトの位置を決定する値をハッシュコードの一致がない場合、また、他のハッシュコード値追加されたオブジェクトと比較され、HashSetのは、オブジェクトが繰り返されていないことを前提としています。オブジェクトが同じハッシュコード値が見つかった場合でも、それが呼び出すequals()同じオブジェクト本当に等しいハッシュコードかどうかを確認する方法を。それらが同じである場合は、HashSetのは、成功した操作を参加させません。(私の本のJavaからの抜粋は、「頭の拳のJava」第二版を悟り)

hashCode()およびequals()関連規定:

  1. 2つのオブジェクトが等しい場合、それはまた、同じハッシュコードである必要があります
  2. 2つのオブジェクトがtrueを返し、2つの方法に等しく、等しいです
  3. ハッシュコード2つのオブジェクトが同じ値を持って、彼らは必ずしも同じではありません
  4. 要約すると、メソッドをオーバーライドされた等しく、この方法は、ハッシュコードをカバーしなければなりません
  5. デフォルトの動作のhashCode()は、ヒープ上のオブジェクトに固有の値を作成することです。ないオーバーライドのhashCode()場合、2つのオブジェクトが(これら2つのオブジェクトが同一のデータを指していても)とにかく同じクラスではありません。

==と違いに等しいです

  1. == 2つの変数が決定されるか、または実施例は、同じメモリ空間に向けられていないメモリ空間への2つの決定された変数または例ポイントの値が同じではないに等しいです
  2. ==)(等号を比較するメモリアドレスを参照し、文字列の内容と比較され
  3. 同じ参照番号は(==等号を意味する)の値を参照するには、同一であり、

根底にあるのHashMapの実現

JDK1.8前

前JDK1.8  HashMap 底がある  配列と連結リスト  一緒に使用している  チェーンのハッシュハッシュコードキーによって得られたハッシュマップは、ハッシュ値を処理外乱関数経過し、次いで(N - 1)によりハッシュ&現在の要素記憶された位置を決定する(nはここでは配列の長さを意味する)、現在の要素の位置が存在する、それは決定されますキー要素が同じであるとしても格納される要素のハッシュ値は、同じ単語、直接カバレッジ場合、ジッパーを介して競合を解決するために、同じ方法ではありません。

いわゆる摂動関数は、ハッシュ方法を指すのHashMapです。ハッシュ関数を用いる方法は、摂動関数ワードが衝突を低減することができる使用して、いくつかの実施のhashCode()メソッドの後に比較的不良の乱れを防止することです。

ハッシュソースのJDK 1.8 HashMapの方法:

より簡便法に比べて、ハッシュJDK 1.8 JDK 1.7ハッシュ法が、同じ原理。

    static final int hash(Object key) {
      int h;
      // key.hashCode():返回散列值也就是hashcode
      // ^ :按位异或
      // >>>:无符号右移,忽略符号位,空位都以0补齐
      return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
  }

JDK1.7のHashMapののハッシュ・ソース方式の比較。

static int hash(int h) {
    // This function ensures that hashCodes that differ only by
    // constant multiples at each bit position have a bounded
    // number of collisions (approximately 8 at default load factor).

    h ^= (h >>> 20) ^ (h >>> 12);
    return h ^ (h >>> 7) ^ (h >>> 4);
}

すべての後に4回を妨げ、ため、ハッシュ法JDK1.8と比較すると、JDK 1.7のハッシュ方式の性能は、少し弱くなります。

いわゆる  「ジッパー方法は」  ある:意志のリストと配列を組み合わせます。すなわち、リンクされたリスト配列を作成し、アレイ内の各セルは、リンクされたリストです。あなたはハッシュ衝突が発生した場合、指定できる値は、競合のリストに追加されます。

JDK1.8後

以前のバージョンに比べて、検索時間を短縮するためにリンクされたリストに、(デフォルトは8である)の鎖長が閾値よりも大きい場合、ハッシュ衝突を解決するJDK1.8後赤黒木の大幅な変更を行いました。

JDK1.8後のTreeMap、TreeSetの基礎となるHashMapのは赤黒木を使用していました。いくつかのケースでは二分探索木は、線形構造に縮退ため赤黒木は、欠陥を解決するために二分探索木です。

推奨読書:

HashMapの長さは2の累乗である理由

効率的なアクセスのHashMap、データを入れしようとすることですできるだけ少ない影響を、可能にするために均等に分配されます。我々はまた、おそらく一般的なアプリケーションは、衝突を発生することは困難である限り、ハッシュ関数マッピングが緩んでより均等にあったように、40億の周りにマッピング空間まで追加、-2147483648 2147483647の値の範囲のハッシュ値、トップ上での話します。しかし、問題は、40億個の長さの配列があり、メモリが収まらされていません。だから、ハッシュ値が直接に使用することはできません。また、配列の長格納する剰余を得るために、使用前に最初のモジュロ演算を行うには、配列インデックスに対応する位置です。この配列の添字をして算出されます (n - 1) & hash「」(N配列は、長さを表します)。HashMapの長さが2のべき乗である理由も説明しています。

どのようにこのアルゴリズムは、それを設計する必要がありでしょうか?

まず、我々は達成するためにモジュロ演算%を使用するのではと思うかもしれません。しかし、フォーカスここで:「モジュロ(%)除数が2のべき乗である場合、動作はその除数AND(&)動作(即ち、ハッシュ%の長さ==ハッシュ・(長さの減少に相当し、 -1) 。長さが2のn乗であることを条件とする。)」  と  バイナリビット操作と、作業効率に対する%はHashMapの長さが2の累乗である理由を説明している、改善することができます。

無限ループの問題でマルチスレッド動作の結果をハッシュマップ

主な理由は、同時焼き直しが円形のリンクリストをもたらすの要素との間に形成されていることです。しかし、この問題1.8解くのをjdkが、HashMapのは、まだ、このようなデータの損失など、他の問題が発生しますので、まだマルチスレッド、マルチスレッド使用中のHashMapの使用はお勧めしません。並行環境はConcurrentHashMapのをお勧めします。

詳細については、以下を参照してください。https://coolshell.cn/articles/9606.html

ConcurrentHashMapとHashtableの違い

ConcurrentHashMapとHashtableの違いは、主にスレッドセーフを達成するために様々な方法で反映されます。

  • 基礎となるデータ構造:  のConcurrentHashMapはJDK1.7底使用の  セグメントの配列リスト+  実装構造等JDK1.8 HashMap1.8、リンクされたリスト配列+ /赤と黒の二分木で使用されるデータ構造を。ハッシュテーブルハッシュマップデータ構造の根底にあると以前使用JDK1.8に類似している  配列+鎖  形態、アレイは、対象のHashMap、主鎖は、ハッシュ衝突が存在解決することであるです。
  • スレッドセーフな(重要な)を達成する方法:  ①  JDK1.7、ConcurrentHashMapの(サブロック)  全体バケットアレイに分割されたセグメント(セグメント)は、各ロックは、コンテナをロックたデータの一部、マルチスレッドアクセスで異なるセグメントからのコンテナデータは、そこに競合をロックし、同時実行率を改善しないであろう。 JDK1.8は、時間セグメントの概念を放棄したが、直接リンクされたリストデータ構造同時実行制御を実装するノードアレー+ +赤黒木とCASを運営使用して同期していることができます。(後で同期ロックのJDK1.6は、最適化の多くを行うために)  だけに、あなたはまだJDK1.8内のデータ構造セグメントを見ることができますが、最適化され、スレッドセーフなHashMapのような全体のルックスが、プロパティを単純化しています旧バージョンとの互換性;②  ハッシュテーブル(同ロック)  :使用スレッドの安全性を確保するために同期化、効率は非常に低いです。アクセス同期方法にあるスレッドが、他のスレッドでもアクセス同期方法、ブロックされる可能性があることも、このようプットを使用して要素を追加するなど、ポーリング状態を入力すると、あなたが使用要素は入れて別のスレッドを追加することはできません、あなたは競争がますます熾烈になり、getを使用することはできません効率を下げます。

基礎となるデータ構造のセットは、フレームをまとめました

コレクション

1.一覧

  • ArrayListに:  オブジェクト配列
  • ベクター:  オブジェクト配列
  • LinkedListの:  二重にリンクされたリスト(JDK1.6の前に循環リストのために、JDK1.7がサイクルをキャンセル)

2.設定

  • HashSetの(ランダム、一意):  ベースHashMapのは、ハッシュマップの下にある記憶素子を用いて実現しました
  • LinkedHashSetの:  LinkedHashSetのはHashSetのから継承され、その内部には、のLinkedHashMapによって達成されます。その内部にはまだ差の少し同じHashMapのベースの実装ですが、私たちが前に言ったのLinkedHashMapと少し似て
  • TreeSetの(オーダーのみ):  赤黒木(自己均衡バイナリーツリーソート)

地図

  • HashMapのは:  ハッシュマップのアレイからなるアレイによってJDK1.8のHashMap +リストが主である前に、リストは、主に解決ハッシュ衝突(コンフリクトを解決する「ジッパー法」)が存在します。JDK1.8は、検索時間を短縮する赤黒木リストに、(デフォルトは8である)の鎖長が閾値よりも大きい場合、ハッシュ衝突を解決する際に大幅な変更を行った後
  • AのLinkedHashMap:  それはまだ、基礎となる構造に基づいているので、ハッシュマップから継承のLinkedHashMapハッシュジッパーとリストまたは赤黒木から成るアレイです。さらに、上記構造は、キーオーダーに維持することができるように上記構造、二重リンクリストの増加に基づいてのLinkedHashMap、。同時にリンクされたリストの操作に対応することによって、アクセス順序は、関連する論理を実現します。詳細を見ることができます:「のLinkedHashMap詳細なソースコード解析(JDK1.8)」
  • ハッシュテーブル:  HashMapのアレイからなるアレイ+リストが主であり、リストは、解決ハッシュ衝突に主に存在します
  • TreeMapの:  赤黒木(自己均衡バイナリーツリーソート)

どのセットを選択するには?

それは、ソート選択HashMapのに選択のConcurrentHashMapのセキュリティスレッドを確保する必要性を必要としないとき。場合は、選択する主な機能セットによれば、例えば、我々は、コレクションの選択にキーに必要な地図インターフェース要素の値になってで、選択肢のTreeMapをソートする必要性我々は唯一、あなたはコレクションは、コレクションインターフェイスを実装する選択要素の値を格納する必要が、あなただけの要素がTreeSetのかHashSetのようなインターフェイスセットを選択セットを達成することを確認する必要があり、あなたは、Listインタフェースを実装し、その後に合わせてそれらを実装するなどのArrayListやLinkedListのように、選択する必要はありませんこれは、選択するインタフェースのコレクションを提供しています。

 

 

 

 

 

 

 

 

 

 

公開された96元の記事 ウォン称賛32 ビュー30000 +

おすすめ

転載: blog.csdn.net/qq_41345773/article/details/104989982