Javaの基本的な16コレクション(ArrayList、LinkedList、HashSet、HashMap)

プログラミングが好きなあなたのように!
SpringBoot実用的なコースは学習https://edu.csdn.net/course/detail/31433
SpringCloud入門コースを学びhttps://edu.csdn.net/course/detail/31451を


序文

たくさんのデータを保存したとき、最初に配列について考えました。ただし、配列の長さは固定されており、不確定な量のデータを保存すると問題が発生します。
この記事では、Javaコレクションフレームワークのアーキテクチャを理解し、List、Set、およびMapインターフェイスの違いを理解し、ArrayList、LinkedList、HashSet、およびHashMapの使用法、データ構造、および実装原則に焦点を当てます。

集合的枠組みシステム

ここに写真の説明を挿入

インターフェース機能:

  • コレクションインターフェイス
    は、コレクションの一般的なメソッドを定義します。たとえば、追加、削除、コレクションの数などです。
  • リストインターフェイス
    を並べ替えたり、重複データを追加したりできます
  • 設定したインターフェースに
    個別にアクセスしたり、データを繰り返したりすることはできません

  • キーを介してアクセスされる、インターフェイスのキーと値のペアをマップします

コレクションインターフェイスの主なメソッド:

方法 前書き
boolean add(Object obj) オブジェクトを追加する
boolean addAll(Collection c) 別のコレクションにすべてのオブジェクトを追加する
boolean remove(Object obj) オブジェクトを削除する
boolean removeAll(Collection c) コレクション内のすべてのオブジェクトを削除します
void clear() すべてのオブジェクトを削除します
int size() 保存されたオブジェクトの数
boolean contains(Object obj) オブジェクトが存在するかどうかを確認します
Object [] toArray() コレクション内のオブジェクトを配列として返します

リストインターフェース

下付き文字で操作したり、重複データを追加したり、
メインメソッドを並べ替えたりできます

方法 前書き
void add(int index、Object obj) 特定の場所にオブジェクトを追加します
オブジェクトget(int index) 特定の位置にあるオブジェクトを返す
オブジェクトremove(int index) 特定の位置にあるオブジェクトを削除します
オブジェクトセット(intインデックス、オブジェクトオブジェクト) 特定の位置にあるオブジェクトを置き換える
リストsubList(int start、int end) コレクションの一部を傍受する
int indexOf(Object) コレクション内のオブジェクトの位置を返します
boolean contains(Object obj) オブジェクトが存在するかどうかを確認します

ArrayListクラス

ArrayListクラスは、Listインターフェイスの実装クラスであり、開発中に非常に使用されるコレクションです。
ArrayListのデータ構造は次のとおりです
。1次元配列

ArrayListの長所と短所:

  • 利点:高速アクセス速度、継続的なストレージスペース、添え字による直接配置
  • 短所:削除と挿入のパフォーマンスが低下し、大量のデータを前後に移動する必要があります

作成方法:

ArrayList arrayList = new ArrayList();

または

ArrayList arrayList = new ArrayList(默认容量);

データの追加:

add(Object 数据)				添加数据到末尾,参数是Object类型,可以添加任何类型的数据。
add(int 下标,Object 数据)	在特定位置添加数据
addAll(Collection 集合)		添加一个集合中所有数据

データを変更します。

set(int 下标,Object 数据)		修改特定位置上数据

データへのアクセス:

get(下标)				返回某个下标上的数据

データ数:

int size()				数据个数

データの削除:

remove(int 下标)			删除特定位置上的数据
clear()					删除所有数据

コレクションをトラバースする:
foreachループ

for(Object obj : list){
	System.out.println("集合中的数据:"+obj);
}

通常のforループ

int size = list.size();
for(int i = 0;i < size;i++){
	Object obj = list.get(i);
	System.out.println("集合中的数据:"+obj);
}

ArrayListソースコード分析:
データを保存する方法は?オブジェクトタイプの1次元配列

transient Object[] elementData;

配列の初期の長さはどれくらいですか?10

private static final int DEFAULT_CAPACITY = 10;

ArrayListはどのように動的に拡張されますか?データ数が元の容量を超えると、容量が元の容量の1.5倍に拡張され、データが新しいアレイにコピーされます。

private void grow(int minCapacity) {
     // overflow-conscious code
     int oldCapacity = elementData.length;
     int newCapacity = oldCapacity + (oldCapacity >> 1); //扩容1.5倍
     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:
     elementData = Arrays.copyOf(elementData, newCapacity); //复制数据到新数组中
}

ベクトルコレクション

VectorコレクションはArrayListに似ています。

  1. データ構造はすべて1次元配列です
  2. 方法はまったく同じです

差:

  1. ArrayListはスレッドセーフではなく、Vectorはスレッドセーフです
  2. ArrayListのパフォーマンスが向上します

ジェネリックコレクション

次のコードの何が問題になっている可能性がありますか?

List list = new ArrayList();
list.add(100);
list.add("123");
int n = (int)list.get(1); //存在类型转换的错误
String s = (String)list.get(0); //存在类型转换的错误

非ジェネリックコレクションの場合、追加するデータの種類に制限はありません。型変換のためにデータを取り出す場合、型の非互換性の問題があります。

ジェネリックコレクションを使用すると、この問題を解決できます。

作成方法:

ArrayList<类型> arrayList = new ArrayList<类型>();

例えば:

ArrayList<String> arrayList = new ArrayList<String>();
ArrayList<Integer> arrayList = new ArrayList<Integer>();
后面的类型可以省略
ArrayList<Integer> arrayList = new ArrayList<>(); 

利点:

  1. 追加できるデータは1種類のみで、間違いを犯しにくい
  2. 型変換なし、パフォーマンスの向上
ArrayList<Person> arrList = new ArrayList<Person>();
arrList.add(new Person("张三",20));
arrList.add(new Person("张大三",21));
arrList.add(new Person("张小三",23));
arrList.add(new Person("张三三",26));
arrList.add(100);  //编译错误,不允许添加其他类型
//读取Person对象
Person person = arrList.get(3);
person.hello();
//删除
arrList.remove(0);
//遍历
for(Person per : arrList){
	per.hello();
}

LinkedList

LinkedListのデータ構造は次のとおりです。
二重リンクリスト
ここに写真の説明を挿入
ここに写真の説明を挿入
ここに写真の説明を挿入

LinkedListの長所と短所:

  • 利点:削除と挿入の速度が速く、前後のポイントを変更するだけで、データを移動する必要がありません
  • 短所:アクセス速度が遅く、順番に前後に移動する必要があり、効率が低くなります。

LinkedListメソッド

方法 前書き
void addFirst(Object obj) 最初の位置にオブジェクトを追加します
void addLast(Object obj) 最後の位置にオブジェクトを追加します
オブジェクトremoveFirst() 最初の位置にあるオブジェクトを削除します
オブジェクトremoveLast() 最後の位置にあるオブジェクトを削除します
オブジェクトgetFirst() オブジェクトを最初の位置に配置します
オブジェクトgetLast() オブジェクトの最後の位置を取得します
void push(Object obj) スタック、ファーストイン、ラストアウト
オブジェクトpop() スタックから、最初から最後まで

LinkedListソースコードの調査

//内部类,保存数据和前后指针
private static class Node<E> {
    E item;
    Node<E> next;
    Node<E> prev;
    Node(Node<E> prev, E element, Node<E> next) {
        this.item = element;
        this.next = next;
        this.prev = prev;
    }
}

要素を挿入

//在succ节点前,插入新节点
void linkBefore(E e, Node<E> succ) {
    final Node<E> pred = succ.prev;  	//succ前一个节点
    //创建新节点,prev指向succ前面节点,next指向succ
    final Node<E> newNode = new Node<>(pred, e, succ); 
    succ.prev = newNode;     		//succ的prev指向新节点
    if (pred == null)
        first = newNode;  		 		//前面没有节点,新节点就是首节点
    else
        pred.next = newNode;  		//否则succ前面节点的next指向新节点
    size++;									//数量加1
    modCount++;
}

要素を挿入

//删除x节点
E unlink(Node<E> x) {
     final E element = x.item;
     final Node<E> next = x.next;
     final Node<E> prev = x.prev;
     if (prev == null) {       //x前面节点的next指向x节点的后面节点
         first = next;
     } else {
         prev.next = next;
         x.prev = null;
     }
     if (next == null) {       //x后面节点的prev指向x节点的前面节点
         last = prev;
     } else {
         next.prev = prev;
         x.next = null;
     }
     x.item = null;
     size--;
     modCount++;
     return element;
 }

インターフェースの設定

セットは重複データを追加できず、内部のデータに個別にアクセスすることはできません

Setインターフェイスの一般的に使用される実装クラスは次のとおりです。

  • HashSet順不同セット
  • TreeSetは自動的にセットをソートします
  • LinkedHashSetは、追加順序のセットを保持できます

HashSet

順序付けされていない場合、保存場所はハッシュアルゴリズムによって計算されます
。コレクションに追加されるデータは、hashCodeおよびequalsメソッドを実装する必要があります。
下部の実装はHashMapであり、データはHashMapのキーに保存されます。

public class HashSet<E> extends AbstractSet<E>
{
   
    private transient HashMap<E,Object> map;
	private static final Object PRESENT = new Object();
    public HashSet() {
        map = new HashMap<>();
    }
    public boolean add(E e) {
        return map.put(e, PRESENT)==null;
    }
    ...
}

マップインターフェイス

キーと値のペア構造のアクセスデータ、見つけやすく効率的。
一般的な方法:

方法 前書き
V put(Kキー、V値) 指定された「キーと値」のペアをマップに保存します
V get(オブジェクトキー) 指定されたキーによってマップされた値を返します
V remove(オブジェクトキー) 指定されたキーに従って、この「キーと値」のペアをマップから削除します
ブールcontainsKey(オブジェクトキー) このマップに指定されたキーが含まれているかどうかを確認します
ブールcontainsValue(オブジェクト値) このマップに指定された値が含まれているかどうかを確認します
ブールisEmpty() このマップに要素があるかどうかを確認します
int size() マップ内の「キーと値」のペアの数を取得します
void clear() マップ内のすべての「キーと値」のペアをクリアします
keySet()を設定します このマップに含まれるキーのコレクションを返します
コレクションvalues() このマップの値のコレクションを返します

HashMap

ハッシュテーブルの形式でデータにアクセスするには、多くのコレクションが使用されます。
作成方法:

HashMap<键类型,值类型> hashmap = new HashMap<>();

指示:

//创建HashMap保存人的对象
HashMap<String,Person> map = new HashMap<String,Person>();
Person person1 = new Person("张三",20);
Person person2 = new Person("李四",22);
Person person3 = new Person("王五",20);
//添加人到集合中
map.put(person1.getName(), person1);
map.put(person2.getName(), person2);
map.put(person3.getName(), person3);
//通过键访问值
map.get("张三").hello();
//删除
map.remove("李四");
//添加重复的键,将新的值覆盖原来的值
map.put("李四", new Person("李四",33));
System.out.println("长度:" + map.size());
//遍历所有的键
for(String key : map.keySet()){
	System.out.println("键: " + key);
}
//遍历所有的值
for(Person per : map.values()){
	per.hello();
}
//遍历所有的键和值
for(String key : map.keySet()){
	System.out.println("键: " + key);
	map.get(key).hello();
}

HashMapの機能

  1. 重複するキーが追加された場合、後で追加された値が前の値を置き換えます。
  2. データは、加算の順序ではなく、ハッシュアルゴリズムで保存されます
  3. 追加されたキーは、hashCodeおよびequalsメソッドを実装する必要があります

HashMapのデータ構造
1次元配列+単一リンクリスト+赤黒木
ここに写真の説明を挿入
データを保存するHashMapプロセス

  1. キーと値のペアのデータを追加する場合、最初にキーのhashCodeメソッドが呼び出され、配列の添え字が計算されます。
  2. 下付き文字のデータが空の場合は、直接保存してください
  3. 下付き文字にデータがある場合、呼び出されたキーの等しい値がその位置にあるキーと比較されます
  4. equalsがtrueを返す場合、古いデータは新しいデータで上書きされます
  5. equalsがfalseを返す場合は、古いデータの後ろに新しいデータを配置して、リンクリストを作成します
  6. リンクリストの長さが8を超えると、自動的に赤黒木に変換されます(java8の最適化)

HashMapソースコード分析

//添加数据
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
  Node<K,V>[] tab; Node<K,V> p; int n, i;
  if ((tab = table) == null || (n = tab.length) == 0)
      n = (tab = resize()).length;                  // 获得数组长度
  if ((p = tab[i = (n - 1) & hash]) == null)     //hashCode对数组长度-1取模获得下标i
      tab[i] = newNode(hash, key, value, null);   //该位置为空就直接添加数据
  else {
      Node<K,V> e; K k;
      if (p.hash == hash &&
          ((k = p.key) == key || (key != null && key.equals(k))))  //不为空就调用equals比较键
          e = p;																				 //键相同就赋值给e,后面直接覆盖value
      else if (p instanceof TreeNode)
          e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
      else {
          for (int binCount = 0; ; ++binCount) {
              if ((e = p.next) == null) {
                  p.next = newNode(hash, key, value, null);  //键不相同就放到后面,形成链表
                  if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st    
                      treeifyBin(tab, hash);	   //链表长度超过8,转换为红黑树
                  break;
              }
              if (e.hash == hash &&
                  ((k = e.key) == key || (key != null && key.equals(k))))
                  break;
              p = e;
          }
      }
      if (e != null) { // existing mapping for key
          V oldValue = e.value;
          if (!onlyIfAbsent || oldValue == null)
              e.value = value;        //覆盖旧的value
          afterNodeAccess(e);
          return oldValue;
      }
  }
  ++modCount;
  if (++size > threshold)
      resize();
  afterNodeInsertion(evict);
  return null;
}

ハッシュ表

HashtableとHashMapの使用法と構造は同じです。
違い:

  1. HashMapはスレッドセーフではありません、Hashtableはスレッドセーフです
  2. HashMapはnullキーと値を追加できますが、Hashtableはnullキーと値を追加できません

TreeMap

特点:添加数据后,会自动对键进行排序
数据结构:红黑树
ここに写真の説明を挿入
使用时需要注意:

  1. 键必须实现Comparable接口
  2. 键如果和已存在的键相等,TreeMap就放弃添加

LinkedHashMap

继承于HashMap,通过额外的链表保留键的添加顺序。
ここに写真の説明を挿入

如何选择集合

在开发过程中,需要根据实际业务场景,结合集合的特点选择集合

  • 可以排序,可以添加重复数据,可以随机访问 ----- List
    • 对数据访问要求高 ----- ArrayList
    • 对插入和删除要求高 ----- LinkedList
  • 不能添加重复的数据,不需要随机访问 ------ Set
    • 没有顺序 ----- HashSet
    • 可以进行排序 ----- TreeSet
    • 保留添加顺序 ----- LinkedHashSet
  • 可以进行快速查找 ,以键值对保存------ Map
    • 键没有顺序 ----- HashMap
    • 键可以排序 ----- TreeMap
    • 键保留添加顺序 ----- LinkedHashMap

结束

集合是Java的重点内容,尤其是ArrayList和HashMap这两个集合应用非常广泛,是否掌握了就通过作业检查了。

  1. 定义歌曲类,属性:歌曲名、歌手名、播放时长(int 类型),定义play方法显示歌曲信息。
    1、添加10首歌到ArrayList集合中
    2、遍历所有的歌曲,显示歌曲信息
    3、输入歌曲名,在集合中查找该歌曲
    4、输入整数索引,删除该位置的歌曲
    5、找出播放时间最长的歌曲
    6、将所有歌曲复制到LinkedList集合中
  2. コレクションをHashMapに変更し、曲名をキーとして使用し、曲を値として使用します
    。1。コレクションに10曲を追加します
    。2。すべての曲をトラバースして曲情報を表示し
    ます。3 曲名を入力して、コレクション内の曲
    。4 。曲名を入力し、曲を削除します。

他のJavaの知識を学ぶ必要がある場合は、ここでJavaの概要に関する非常に詳細な知識を調べてください。

おすすめ

転載: blog.csdn.net/u013343114/article/details/112602465