Java コレクションを 1 つの記事で理解する (詳細な画像とテキスト)

Javaコレクションフレームワーク図

図からわかるように、これは主にコレクションとマップの 2 つのカテゴリに分かれており、Collection主にオブジェクトのセットとMapキーと値のペアを格納するために使用されます。

2つをさらに細分化する

コレクションインターフェイス:

マップインターフェース 

 

 収集フレームワークの概要

1. Collectionインタフェースのインタフェースオブジェクトのコレクション(シングルカラムコレクション)

  1. リストインターフェイス: 要素はエントリの順序に従って順番に保存され、整然とした繰り返し可能です。
    1. LinkedList インターフェイス実装クラス、リンク リスト、挿入と削除、同期なし、スレッド アンセーフ
    2. ArrayList インターフェース実装クラス、配列、ランダムアクセス、同期なし、スレッドアンセーフ
    3. ベクトル インターフェイスは、配列のような、同期された、スレッドセーフを実装します。
  2. セットインターフェイス: 1 回のみ受信、順序なし、反復不可、内部ソート
    1. HashSet はハッシュ テーブル (配列) を使用して要素を格納します
      1. LinkedHashSet は、リンクされたリスト内の要素の挿入順序を維持します。
    2. TreeSet の基礎となる実装はバイナリ ツリーであり、要素は並べ替えられます。

2. Map インターフェイスのキーと値のペアのコレクション (2 列コレクション)

  1. ハッシュテーブルインターフェース実装クラス、同期、スレッドセーフ
  2. HashMap インターフェイス実装クラス、同期なし、スレッドは安全ではありません
    1. LinkedHashMap を注文しました
  3. TreeMap の赤黒ツリーはすべてのキーをソートします

1. 収集インターフェース

//因为Collection是接口,不能实例化,所以我们用他的一个实现类ArrayList来演示
List list = new ArrayList<>();
list.add("mk");
list.add(true);
list.add(12.3);

指定した種類のデータを保存することもできます 

List<String> list = new ArrayList<>();
list.add("mk");

 一般的な方法

int サイズ();

コレクションのサイズを取得する

ブール値 isEmpty();

空かどうかを判断する

ブール値には (オブジェクト var1) が含まれます。

が含まれているかどうかを判断します

Object[] toArray();

コレクションを配列に変換する

ブール値 add(E var1);

要素の追加

ブール値 addAll(コレクション var1);

コレクションのすべての要素を追加する

ブール値の削除(オブジェクト var1);

コレクションから要素を削除する

ブール値の削除(int インデックス);

指定されたインデックスにある要素をコレクションから削除します

ブール値 RemoveAll(コレクション var1);

コレクションのすべての要素を削除する

ボイドクリア();

コレクションをクリアする

ブール値 containsAll(コレクション var1);

別のコレクションの要素が含まれているかどうかを判断する

ブール値と等しい(オブジェクト var1);

それらが同じかどうかを判断する

デフォルトの Spliterator スプリッテレータ();

このコレクションの区切り文字を取得します

デフォルトのストリーム stream();

ストリームに変換

デフォルトのストリームParallelStream();

ストリーム並列ストリームに変換

テスト

 
public class Test {
    public static void main(String[] args) {
        //定义一个集合并向上转型
        Collection<String> obj = new ArrayList<>();
        //1.int size();    获取集合大小
        int size = obj.size();
        //2.boolean isEmpty();    判断是否为空
        boolean empty = obj.isEmpty();
        //3.boolean contains(Object var1);    判断是否包含
        boolean contains = obj.contains(null);
        //4.Object[] toArray();    将集合转换为数组
        Object[] objects = obj.toArray();
        //5.boolean add(E var1);    向集合增加元素
        boolean result = obj.add("Hello World");
        //6.boolean remove(Object var1);    向集合移除元素
        boolean remove = obj.remove(null);
        //7.boolean containsAll(Collection<?> var1);    判断是否包含另一个集合的元素
        boolean containsResult = obj.containsAll(new ArrayList<>());
        //8.boolean addAll(Collection<? extends E> var1);    添加一个集合的全部元素
        boolean addAllResult = obj.addAll(new ArrayList<>());
        //9.boolean removeAll(Collection<?> var1);    删除一个集合的全部元素
        boolean removeAllResult = obj.removeAll(new ArrayList<>());
        //10.void clear();    清空集合
        obj.clear();
        //11.boolean equals(Object var1);    判断是否相同
        boolean equalsResult = obj.equals(null);
        //12.default Spliterator<E> spliterator();    得到该集合的分离器
        Spliterator<String> spliterator = obj.spliterator();
        //13.default Stream<E> stream();    转换为Stream流
        Stream<String> stream = obj.stream();
        //14.default Stream<E> parallelStream();    转换为Stream并行流
        Stream<String> stringStream = obj.parallelStream();
    }
}

トラバーサル法

2 つの走査方法:

  1. イテレータ
  2. 拡張された for ループ (foreach ループ)

方法 1: イテレータ

        //1. 先得到collection对应的迭代器
        Iterator iterator = collection.iterator();
        //2. 开始遍历
            //判断是否还有下一个元素
        while (iterator.hasNext()) {
            //返回下一个元素
            Object next =  iterator.next();
            System.out.println(next);
            
        }
        //重置iterator
        iterator = collection.iterator();

効果

ポインターに相当し、コレクションを走査するために使用されます。

1. なぜ反復子が必要なのでしょうか?

実際のアプリケーションでは、多くの場合、ビジネス ニーズを満たすためにコンテナーのトラバーサルを判断する必要があります。

2. 反復を実装するにはどうすればよいですか?

Iterator クラスには hasNext() と next() という 2 つのメソッドがあります。これは、トラバーサル プロセスでは最初にそれが空かどうかを判断する必要があるためです。空でない場合は、トラバースを続行できます。

CollectionクラスのremoveIf()メソッドはjdk1.8以降でしか利用できないため、Iteratorクラスにはremove()メソッドがあり、論理削除の要件を満たす必要があります。

3. イテレータを再度使用する場合は、イテレータをリセットする必要があります。

イテレータを一度使用すると、ポインタは最後の要素を指すため、再度使用する場合はリセットする必要があり、そうしないとエラーが報告されます。

4. コード生成用のショートカットキー

itit


public class Test {
    public static void main(String[] args) {
        Collection collection = new ArrayList();
        collection.add(new Book("三国演义","罗贯中",10.1));
        collection.add(new Book("小李飞刀","古龙",5.1));
        collection.add(new Book("海贼王","尾田",34.6));

        //1. 先得到collection对应的迭代器
        Iterator iterator = collection.iterator();
        //2. 开始遍历
            //判断是否还有下一个元素
        while (iterator.hasNext()) {
            //返回下一个元素
            Object next =  iterator.next();
            System.out.println(next);
            
        }
        //重置iterator
        iterator = collection.iterator();
    }

}

class Book {
    String name;
    String author;
    double price;

    public Book(String name, String author, double price) {
        this.name = name;
        this.author = author;
        this.price = price;
    }

    @Override
    public String toString() {
        return "Book{" +
                "name='" + name + '\'' +
                ", author='" + author + '\'' +
                ", price=" + price +
                '}';
    }
}

方法 2: foreach ループ

        for (Object object : collection) {
            System.out.println(object);
        }

拡張された for ループは foreach ループであり、イテレータ iterator を置き換えることができます。

特徴: Enhanced for はイテレータの簡易版であり、本質は同じで、最下層もイテレータです。配列とコレクションの両方を使用できます。

ショートカットキー:

collection.for 

public class Test {
    public static void main(String[] args) {
        Collection collection = new ArrayList();
        collection.add(new Book("三国演义","罗贯中",10.1));
        collection.add(new Book("小李飞刀","古龙",5.1));
        collection.add(new Book("海贼王","尾田",34.6));

        for (Object object : collection) {
            System.out.println(object);
        }
    }

}

class Book {
    String name;
    String author;
    double price;

    public Book(String name, String author, double price) {
        this.name = name;
        this.author = author;
        this.price = price;
    }

    @Override
    public String toString() {
        return "Book{" +
                "name='" + name + '\'' +
                ", author='" + author + '\'' +
                ", price=" + price +
                '}';
    }
}

収集用途シナリオ分析

 

1.1. リストインターフェース

Collection インターフェイス、List インターフェイス、Set インターフェイスにはすべてメソッドがありますが、List インターフェイスと Set インターフェイスには、他にはない独自のメソッドがあります。

特徴

  1. List コレクション クラス内の要素は順序付けされています (つまり、追加の順序と削除の順序が一致しています)。
  2. 再現可能
  3. List コレクション内の各要素には、対応する順次インデックスがあります。つまり、インデックス付けがサポートされています。

        つまり、list.get(3) を使用して 4 番目の要素を取得できます。

一般的な方法

Collection インターフェイスのメソッドに加えて、List インターフェイスにも独自のメソッドがあります。

List インターフェイスは順序付けされているため、インデックスを使用して多くのメソッドを使用できます。

package edu.tjdz.javaSE.collection;
 
import java.util.*;
 
/*
测试List接口中的常用方法
    1、List集合存储元素特点:有序可重复
        有序:List集合中元素由下标。
          从0开始,以1递增。
        可重复:存储一个1,还可以在存储一个1.
    2、List即是Collection接口中的子接口,那么肯定List接口有自己“特色”的方法:
        以下只列出List特有的常用的方法
        void add(int index, E element)  在列表的指定位置添加元素(第一个参数是下标)
        Object get(int index)     根据下标获取元素(元素的下标,从0开始,以1递增)
        int indexOf(Object o)   //获取指定对象第一次出现的索引
        int lastIndexOf(Object o)     //获取指定对象最后一次出现的索引
        Object remove(int index)      //删除指定下标位置的元素
        Object set(int index, Object element)   //修改指定位置元素(元素下标,修改的值)
 */
public class CollectionTest07 {
    public static void main(String[] args) {
        //创建List集合
        //List myList = new LinkedList();
        //List myList = new Vector();
        List myList = new ArrayList();
 
        //添加元素
        myList.add("A");  //默认都是向集合尾部添加元素
        myList.add("B");
        myList.add("C");
        myList.add("D");
        myList.add("A");
 
        //在列表的指定位置添加元素(第一个参数是下标)
        //这个方法使用不多,因为对于ArrayList集合来说,效率较低(因为ArrayLIst底层是数组,添加的时候会涉及到元素位移的问题)
        myList.add(1,"KING");
 
        //迭代
        Iterator it = myList.iterator();
        while(it.hasNext()){
            Object elt = it.next();
            System.out.println(elt);
        }
 
        System.out.println("------------------------------");
 
        //根据下标
        Object firstobj = myList.get(0);
        System.out.println(firstobj);  //A
 
        //因为有下标,所以List集合有自己特殊的遍历方式
        //根据下标遍历【List集合特有的方式,Set没有。】
        for(int i=0;i<myList.size();i++){
            Object obj = myList.get(i);
            System.out.println(obj);
        }
 
        //获取指定对象第一次出现的索引
        System.out.println(myList.indexOf("KING"));  //1
 
        //获取指定独享最后一次出现处的索引
        System.out.println(myList.lastIndexOf("A")); //5
 
        //删除指定下标位置的元素
        myList.remove(0);
        System.out.println(myList.size()); //5
 
        System.out.println("================================");
        //修改指定位置元素
        myList.set(0,"Soft");
 
        //索引方式遍历集合
        for(int i=0;i<myList.size();i++){
            Object obj = myList.get(i);
            System.out.println(obj);
        }
    }
}

3 つのトラバース方法

List では、コレクション インターフェイスの 2 つのメソッド (Iterator と foreach ループ) を使用できます。

独自のメソッドもあり、List インターフェイスは順序付けされているため、インデックスによってトラバースできます。

        //遍历集合
        for(int i=0;i<myList.size();i++){
            Object obj = myList.get(i);
            System.out.println(obj);
        }

ArrayList、Vector、LinkedList の違い

1階

お問い合わせ

追加と削除

スレッドの安全性

効率

拡張倍数

配列リスト

配列

素早い

遅い

危険な

高い

パラメータ構造体がある場合、デフォルトのサイズはパラメータで、いっぱいになると 1.5 倍に拡張されます。

パラメータなしで構築した場合、デフォルトのサイズは 0 です。容量は初回は 10 に拡張され、2 回目以降は 1.5 倍になります。

ベクター

配列

素早い

遅い

安全性

低い

パラメータを使用して構築された場合、デフォルトのサイズはパラメータであり、いっぱいになると毎回 2 回展開されます。

パラメーターなしで構築された場合、デフォルトのサイズは 10 です。いっぱいになると、2 倍に拡張されます。

リンクリスト

リンクされたリスト

遅い

素早い

危険な

高い

リンクされたリスト、拡張は不要

配列リスト

 膨張機構

  1. ArrayList は、Object 型の配列 elementData を保持します。
  2. ArrayList オブジェクトを作成するとき、パラメーターなしのコンストラクターが使用される場合、elementData の初期容量は 0 です。初めて追加されるとき、elementData は 10 に拡張されます。再度拡張する必要がある場合、elementData は 1.5 に拡張されます。回。
  3. 指定サイズのコンストラクタを使用する場合、初期の elementData 容量は指定サイズとなりますが、拡張が必要な​​場合はそのまま elementData 容量を 1.5 倍に拡張します。
  4. 展開メソッドには add メソッドと addAll メソッドの 2 つがあります。

2 と 3 はそれぞれ下の写真の 2 つです。

 

 

注: コード内の右シフトは、÷2 を意味します。

ベクター

(1) Vector は拡張可能なオブジェクト配列を実装できます。配列と同様に、コンポーネントには整数インデックスを使用してアクセスできます。ただし、ベクターの作成後に追加または削除操作に対応するために、ベクターのサイズを増減できます。

(2) 同時に、Vector はスレッドセーフです。最下層はロックに synchronized を使用します。

膨張機構

パラメータを使用して構築された場合、デフォルトのサイズはパラメータであり、いっぱいになると毎回 2 回展開されます。

パラメーターなしで構築された場合、デフォルトのサイズは 10 です。いっぱいになると、2 倍に拡張されます。

リンクリスト

根底にあるメカニズム

  1. LinkedList は、その下に二重リンクされたリストを維持します。
  2. LinkedList は、最初のノードと最後のノードをそれぞれ指す 2 つの属性 first と last を維持します。
  3. 各ノード (Node オブジェクト) は、prev、next、item の 3 つの属性を保持します。Prev は前のノードを指し、next は次のノードを指します。最後に、双方向リンク リストが実装されます。
  4. したがって、LinkedList の要素の追加と削除は配列を介して行われず、比較的効率的です。

1.2. インターフェースの設定 

特徴

  1. 順序なし (追加と削除の順序が不一致)
  2. 重複した要素は許可されないため、最大 1 つの null を含めてください。
  3. インデックスがありません。つまり、インデックスを使用してデータを取得することはできません。

一般的な方法

Collection インターフェイスのメソッドに加えて、Set インターフェイスにも独自のメソッドがあります。

 

2 つのトラバース方法

つまり、Collection インターフェイスの 2 つのトラバーサル メソッド、Iterator と foreach ループです。

Set は順序付けされていないため、インデックスを使用して走査することはできません。

インタビューの質問: セットでは繰り返し要素を追加できませんか?

public class SetTest {
    public static void main(String[] args) {
        Set set = new HashSet();
        // Hashset不能添加相同的元素/数据?
        set.add("lucy");//ok
        set.add( "lucy");//no

        set.add(new Dog("tom" ));//OK
        set.add(new Dog( "tom"));//0k


        //再加深一下。非常经典的面试题。
        set.add(new String("hsp"));//ok
        set.add(new String("hsp"));//no

        System.out.println( "set=" + set);
    }
}

class Dog{
    String name;
    Dog(String name){
        this.name = name;
    }
}

出力

set=[hsp, 集合.Dog@4554617c, 集合.Dog@1b6d3586, lucy]

Lucy の場合、アドレスは同じで定数プール内にあるため、重複要素となるため、2 番目のアドレスを追加できません。

Dog の場合、どちらの犬も異なるアドレスを持つ新しいオブジェクトであるため、重複要素とは見なされず、追加できます。

なぜ3番目のペアなのでしょうか?

ハッシュセット

Java_javaにおけるHashSetの概念、実装、運用 hashset_Suekoのブログ - CSDNブログ

  1. HashSet の最下層は HashMap、HashMap の最下層は (配列 + リンク リスト + 赤黒ツリー) です。
  2. HashSet は HashMap に基づいて実装され、Set インターフェイスを実装し、シリアル化とクローン作成も実装します。セットでは重複した値は許可されません。
  3. したがって、HashSet は重複する要素を含まないセットですが、セットの反復順序は保証されていないため、要素の順序は時間の経過とともに変化する可能性があります。
  4. HashSet は HashMap に基づいて実装されているため、null 値が許可され、スレッドセーフではありません。

リンクされたハッシュセット

  1. LinkedHashSet は HashSet のサブクラスです
  2. LinkedHashSet の最下層は LinkedHashMap で、配列 + 二重リンク リストを維持します。
  3. LinkedHashSet は、要素の格納場所を hashCode 値に基づいて決定し、リンク リストを使用して要素 (画像) の順序を維持します。これにより、要素が挿入順に保存されているように見えます。
  4. LinkedHashSet では要素の重複は許可されません

2. マップインターフェース

特徴

注: ここで話しているのは、JDK8 の Map インターフェイス機能です。

  1. マップとコレクションは並列して存在します。マッピング関係を含むデータを保存するために使用されます: Key-Value
  2. Map 内のキーと値は任意の参照型データにすることができ、HashMap$Node オブジェクトにカプセル化されます。
  3. マップ内のキーを繰り返すことはできませんが、マップ内の値は繰り返すことができます。
  4. Map のキーは null にすることができ、値も null にすることができます。キーが null の場合は 1 つだけ、値が null の場合は複数存在できることに注意してください。
  5. String クラスは Map のキーとしてよく使用されます。
  6. キーと値の間には一方向の 1 対 1 の関係があります。つまり、対応する値は指定されたキーを通じて常に見つけることができます。
  7. kv はエントリです

一般的な方法

追加、削除、変更操作:

Object put(Object key,Object value): 指定されたキーと値を現在のマップ オブジェクトに追加 (または変更)

void putAll(Map m): m 内のすべてのキーと値のペアを現在のマップに保存します

Object delete(Object key): 指定されたキーのキーと値のペアを削除し、値を返します。

void clear(): 現在のマップ内のすべてのデータをクリアします

要素クエリ操作:

Object get(Object key): 指定されたキーに対応する値を取得します。

boolean containsKey(Object key): 指定されたキーが含まれるかどうか

boolean containsValue(オブジェクト値): 指定された値が含まれているかどうか

int size(): マップ内のキーと値のペアの数を返します。

boolean isEmpty(): 現在のマップが空かどうかを判断します。

booleanquals(Object obj): 現在のマップとパラメータオブジェクト obj が等しいかどうかを判断します。

メタビューの操作方法:

Set keySet(): すべてのキーで構成される Set コレクションを返します。

Collection value(): すべての値で構成されるコレクションを返します。

SetentrySet(): すべてのキーと値のペアで構成される Set を返します。

よく使用される実装クラス

Map インターフェイスのキーと値のペアのコレクション (2 列コレクション)

  1. ハッシュテーブルインターフェース実装クラス、同期、スレッドセーフ
  2. HashMap インターフェイス実装クラス、同期なし、スレッドは安全ではありません
  3. TreeMap の赤黒ツリーはすべてのキーをソートします

Map インターフェイスの共通実装クラス: HashMap (サブクラス LinkedHashMap)、TreeMap、および Hashtable (サブクラス Properties)。

トラバーサル法

1 つ目: map.KeySet() メソッドを使用してキーを取得します

まず、map.KeySet() メソッドを使用してすべてのキーを取得し、これらのキーを Set コレクションに格納してから、これらのキーを走査し、map.get(key) メソッドを使用して値を取得します。

Set コレクション走査の foreach ループを使用してキーを走査することも、Set コレクションの反復子キーを使用することもできます。

注: この方法はキーのみを取得できるため、対応する値を取得するには繰り返し計算が必要となり非効率であるため、推奨されません。

public static void main(String[] args) {
    Map map = new  HashMap();
    map.put("张三","李四");
    map.put("路飞","女帝");
    map.put("鸣人","雏田");
    map.put("佐助","小樱");
    map.put("邓超","孙俪");


    System.out.println("第一种:用for循环--------------");
    for(Object key : map.keySet()){
        System.out.println(key + "-" + map.get(key));
    }
    
    
    System.out.println("第二种:用迭代器--------------");
    Iterator iterator = map.keySet().iterator();
    while (iterator.hasNext()) {
        Object key =  iterator.next();    
        System.out.println(key + "-" + map.get(key));
    }

}

 

2 番目: map.values メソッドを使用してすべての値を取得します

map.values() メソッドを使用してすべての値を取得し、コレクションに格納し、コレクション インターフェイスの 2 つのトラバーサル メソッドを使用してトラバースします。

注: この方法では削除できるのは値のみであり、キーは削除できないため、お勧めできません。

public static void main(String[] args) {
    Map map = new  HashMap();
    map.put("张三","李四");
    map.put("路飞","女帝");
    map.put("鸣人","雏田");
    map.put("佐助","小樱");
    map.put("邓超","孙俪");

    Collection values = map.values();
    System.out.println("第一种:用for循环--------------");
    for(Object value : values){
        System.out.println(value);
    }
    System.out.println("第二种:用迭代器--------------");
    Iterator iterator = values.iterator();
    while (iterator.hasNext()) {
        Object value =  iterator.next();
        System.out.println(value);
    }

}

 3番目の方法:map.entrySet()メソッドを使用してkyを取り出す

まず、map.entrySet() メソッドを通じて Set コレクションを取得できます。このコレクション内の各要素は、Map 内のキーと値のペアです。次に、Set コレクションをループすることで、各ペアのキーと値を順番に取り出すことができます。このメソッドは foreach ループを使用し、コードは簡潔かつ明確で、Map のキーと値を取得でき、ほとんどの場合、最も一般的で最も望ましいトラバーサル メソッドです。

注: 効率が高いこの方法を使用することをお勧めします。

public static void main(String[] args) {
    Map map = new  HashMap();
    map.put("张三","李四");
    map.put("路飞","女帝");
    map.put("鸣人","雏田");
    map.put("佐助","小樱");
    map.put("邓超","孙俪");

    Set entrySet = map.entrySet();
    System.out.println("第一种:用for循环--------------");
    for(Object entry : entrySet){
        //将entry 转换成 Map.Entry
        Map.Entry m =(Map.Entry) entry;
        System.out.println(m.getKey() + "-" + m.getValue());
    }

    System.out.println("第二种:用迭代器--------------");
    Iterator iterator = entrySet.iterator();
    while (iterator.hasNext()) {
        Object entry =  iterator.next();
        //将entry 转换成 Map.Entry
        Map.Entry m =(Map.Entry) entry;
        System.out.println(m.getKey() + "-" + m.getValue());
    }

}

おすすめ

転載: blog.csdn.net/KangYouWei6/article/details/132561298