プログラミングが好きなあなたのように!
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次元配列です
- 方法はまったく同じです
差:
- ArrayListはスレッドセーフではなく、Vectorはスレッドセーフです
- 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種類のみで、間違いを犯しにくい
- 型変換なし、パフォーマンスの向上
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の機能
- 重複するキーが追加された場合、後で追加された値が前の値を置き換えます。
- データは、加算の順序ではなく、ハッシュアルゴリズムで保存されます
- 追加されたキーは、hashCodeおよびequalsメソッドを実装する必要があります
HashMapのデータ構造
1次元配列+単一リンクリスト+赤黒木
データを保存するHashMapプロセス
- キーと値のペアのデータを追加する場合、最初にキーのhashCodeメソッドが呼び出され、配列の添え字が計算されます。
- 下付き文字のデータが空の場合は、直接保存してください
- 下付き文字にデータがある場合、呼び出されたキーの等しい値がその位置にあるキーと比較されます
- equalsがtrueを返す場合、古いデータは新しいデータで上書きされます
- equalsがfalseを返す場合は、古いデータの後ろに新しいデータを配置して、リンクリストを作成します
- リンクリストの長さが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の使用法と構造は同じです。
違い:
- HashMapはスレッドセーフではありません、Hashtableはスレッドセーフです
- HashMapはnullキーと値を追加できますが、Hashtableはnullキーと値を追加できません
TreeMap
特点:添加数据后,会自动对键进行排序
数据结构:红黑树
使用时需要注意:
- 键必须实现Comparable接口
- 键如果和已存在的键相等,TreeMap就放弃添加
LinkedHashMap
继承于HashMap,通过额外的链表保留键的添加顺序。
如何选择集合
在开发过程中,需要根据实际业务场景,结合集合的特点选择集合
- 可以排序,可以添加重复数据,可以随机访问 ----- List
- 对数据访问要求高 ----- ArrayList
- 对插入和删除要求高 ----- LinkedList
- 不能添加重复的数据,不需要随机访问 ------ Set
- 没有顺序 ----- HashSet
- 可以进行排序 ----- TreeSet
- 保留添加顺序 ----- LinkedHashSet
- 可以进行快速查找 ,以键值对保存------ Map
- 键没有顺序 ----- HashMap
- 键可以排序 ----- TreeMap
- 键保留添加顺序 ----- LinkedHashMap
结束
集合是Java的重点内容,尤其是ArrayList和HashMap这两个集合应用非常广泛,是否掌握了就通过作业检查了。
- 定义歌曲类,属性:歌曲名、歌手名、播放时长(int 类型),定义play方法显示歌曲信息。
1、添加10首歌到ArrayList集合中
2、遍历所有的歌曲,显示歌曲信息
3、输入歌曲名,在集合中查找该歌曲
4、输入整数索引,删除该位置的歌曲
5、找出播放时间最长的歌曲
6、将所有歌曲复制到LinkedList集合中 - コレクションをHashMapに変更し、曲名をキーとして使用し、曲を値として使用します
。1。コレクションに10曲を追加します
。2。すべての曲をトラバースして曲情報を表示し
ます。3 。曲名を入力して、コレクション内の曲
。4 。曲名を入力し、曲を削除します。
他のJavaの知識を学ぶ必要がある場合は、ここでJavaの概要に関する非常に詳細な知識を調べてください。