一、List接口
1. 常见实现
List
接口继承自 Collection
接口,定义了一系列操作有序集合的方法。
List
接口的常见实现包括 ArrayList
、LinkedList
和 Vector
。
①ArrayList
- ArrayList 是 Java 中最常用的动态数组实现之一。
- 它基于数组实现,可以动态增长以容纳任意数量的元素。
- 提供了快速的随机访问,因为它支持通过索引直接访问元素。
- 添加和删除元素的操作可能会比较慢,因为在数组中间插入或删除元素需要移动其他元素。
- 在大多数情况下,
ArrayList
是首选的列表实现,因为它提供了良好的性能和灵活性。
ArrayList<Type> arrayList = new ArrayList<>();
②LinkedList
LinkedList
是一个双向链表实现的列表。- 它提供了快速的插入和删除操作,因为在链表中插入或删除元素不需要移动其他元素。
- 随机访问的性能较差,因为它需要沿着链表从头部或尾部遍历到目标位置。
LinkedList
适用于需要频繁插入和删除元素、不需要频繁随机访问元素的场景。
LinkedList<Type> linkedList = new LinkedList<>();
③Vector
Vector
是 Java 中最早的动态数组实现之一,它在 Java 1.0 中就已经存在了。Vector
是线程安全的,它的方法都被synchronized
关键字修饰,因此可以在多线程环境下安全地使用。Vector
的性能可能不如ArrayList
,因为它的方法都是同步的,会增加一些额外的开销。- 尽管
Vector
提供了线程安全性,但在大多数情况下,ArrayList
更常用,因为大部分情况下并不需要线程安全性,而且ArrayList
的性能更好。
Vector<Type> vector = new Vector<>();
2. 相关方法
①共同的方法
boolean add(E element)
: 将指定的元素追加到列表的末尾。
void add(int index, E element)
: 在指定的索引处插入指定的元素。
E get(int index)
: 返回列表中指定位置的元素。
boolean remove(Object o)
: 从列表中删除第一个出现的指定元素,如果存在的话。
E remove(int index)
: 删除列表中指定位置的元素,并返回被删除的元素。
E set(int index, E element)
: 将指定索引处的元素替换为指定的元素。
boolean contains(Object o)
: 如果列表包含指定的元素,则返回 true。
int indexOf(Object o)
: 返回列表中第一次出现指定元素的索引,如果列表中不包含此元素,则返回 -1。
int size()
: 返回列表中的元素数。
boolean isEmpty()
: 如果列表不包含任何元素,则返回 true。
void clear()
: 从列表中移除所有元素。
Object[] toArray()
: 返回包含列表中所有元素的数组。
void Collections.sort(List<T> list, Comparator<? super T> c)
: 排序。
int Collections.binarySearch(List<? extends Comparable<? super T>> list, T key)
:二分查找。
②ArrayList 和 Vector 独有的方法
void trimToSize()
: 将列表的容量调整为列表的当前大小。
void ensureCapacity(int minCapacity)
: 如果需要,增加列表的容量,以确保它至少能容纳最小容量参数指定的元素数。
③LinkedList 独有的方法
void addFirst(E element)
: 将指定元素插入到列表的开头。
void addLast(E element)
: 将指定元素追加到列表的末尾。
E getFirst()
: 返回列表的第一个元素。
E getLast()
: 返回列表的最后一个元素。
E removeFirst()
: 删除并返回列表的第一个元素。
E removeLast()
: 删除并返回列表的最后一个元素。
void push(E element)
: 将指定元素推入此列表的堆栈顶部。
E pop()
: 从此列表所表示的堆栈处弹出一个元素。
二、Queue接口及Deque接口
Deque接口继承自Queue接口
1. 常见实现
①LinkedList
LinkedList
实现了Deque
接口,因此也可以作为Queue
使用。- 它是基于双向链表的数据结构,支持在队列的两端进行插入和删除操作。
- 在需要同时支持队列和栈操作时,
LinkedList
是一个不错的选择。
LinkedList<Type> linkedList = new LinkedList<>();
②ArrayDeque
ArrayDeque
实现了Deque
接口,因此也可以作为Queue
使用。- 它是基于动态数组的数据结构,支持高效的队列操作,包括在队列的两端进行插入和删除操作。
ArrayDeque
的性能通常比LinkedList
更好,尤其在大量插入、删除操作时。
ArrayDeque<Type> arrayDeque = new ArrayDeque<>();
③PriorityQueue
PriorityQueue
是一个基于优先级堆的无界优先级队列。- 它不是
Deque
接口的实现类,但也可以用作队列。 PriorityQueue
中的元素根据它们的自然顺序或者通过构造时提供的Comparator
进行排序。- 在
PriorityQueue
中,元素插入时会根据优先级进行排序,每次取出的元素都是具有最高优先级的元素。
PriorityQueue<Type> priorityQueue = new PriorityQueue<>();
2. 相关方法
size()
isEmpty()
等存在于 Collection
接口下,所以 Collection
下的各种实现也具有这些方法。
①LinkedList
-
在队列头部和尾部添加元素:
void addFirst(E e)
: 将指定的元素添加到队列的头部。void addLast(E e)
: 将指定的元素添加到队列的尾部。
-
从队列头部和尾部删除元素:
E removeFirst()
: 移除并返回队列的第一个元素。E removeLast()
: 移除并返回队列的最后一个元素。
-
获取队列头部和尾部的元素:
E getFirst()
: 返回队列的第一个元素。E getLast()
: 返回队列的最后一个元素。
-
在队列头部和尾部插入元素:
boolean offerFirst(E e)
: 在队列的头部插入指定的元素。boolean offerLast(E e)
: 在队列的尾部插入指定的元素。
-
从队列头部和尾部检索并删除元素:
E pollFirst()
: 检索并移除队列的第一个元素。E pollLast()
: 检索并移除队列的最后一个元素。
②ArrayDeque
-
在队列头部和尾部添加元素:
void addFirst(E e)
: 将指定的元素添加到队列的头部。void addLast(E e)
: 将指定的元素添加到队列的尾部。
-
获取队列头部和尾部的元素:
E peekFirst()
: 检索但不移除队列的第一个元素,如果队列为空,则返回 null。E peekLast()
: 检索但不移除队列的最后一个元素,如果队列为空,则返回 null。
-
从队列头部和尾部删除元素:
E removeFirst()
: 移除并返回队列的第一个元素。E removeLast()
: 移除并返回队列的最后一个元素。
-
获取队列头部和尾部的元素:
E getFirst()
: 返回队列的第一个元素。E getLast()
: 返回队列的最后一个元素。
-
在队列头部和尾部插入元素:
boolean offerFirst(E e)
: 在队列的头部插入指定的元素。boolean offerLast(E e)
: 在队列的尾部插入指定的元素。
-
从队列头部和尾部检索并删除元素:
E pollFirst()
: 检索并移除队列的第一个元素。E pollLast()
: 检索并移除队列的最后一个元素。
-
检查队列是否为空:
isEmpty()
: 当队列中没有任何元素时,该方法返回 true,否则返回 false。
③PriorityQueue
-
添加元素:
boolean add(E e)
: 将指定的元素添加到队列中。
-
删除元素:
E remove()
: 检索并移除队列的头部元素。E poll()
: 检索并移除队列的头部元素,如果队列为空,则返回 null。
-
获取队列头部的元素:
E peek()
: 检索但不移除队列的头部元素,如果队列为空,则返回 null。
-
队列大小:
int size()
: 返回队列中的元素数量。
-
检查队列是否为空:
isEmpty()
: 当队列中没有任何元素时,该方法返回 true,否则返回 false。
PriorityQueue重载比较方法
import java.util.PriorityQueue;
public class test1 {
public static void main(String[] args) {
// 创建一个 PriorityQueue,并使用 lambda 表达式定义比较器
PriorityQueue<String> pq = new PriorityQueue<String>((s1, s2) -> {
return s1.compareTo(s2);
});
// 向 PriorityQueue 中添加元素
pq.add("apple");
pq.add("banana");
pq.add("pear");
pq.add("grape");
// 输出 PriorityQueue 中的元素(按照字符串长度排序)
while (!pq.isEmpty()) {
System.out.print(pq.remove() + " ");
}
}
}
三、Set接口
1. 常见实现
①HashSet
HashSet
基于哈希表实现,不保证元素的顺序,允许使用null
元素。HashSet
提供O(1)
时间复杂度的插入、删除和查找操作。- 由于
HashSet
不保证元素的顺序,因此它的性能通常比TreeSet
更好。 - 适用于需要高性能插入、删除和查找操作,且不关心元素顺序的情况。
HashSet<Type> hashSet = new HashSet<>();
②TreeSet
TreeSet
基于红黑树(Red-Black Tree)实现,可以确保元素按照自然顺序或指定的比较器顺序进行排序。TreeSet
不允许使用null
元素。TreeSet
提供O(logn)
时间复杂度的插入、删除和查找操作。- 由于
TreeSet
维护了元素的顺序,因此它的性能通常比HashSet
差一些,但可以确保元素按照特定的顺序排列。 - 适用于需要保证元素顺序并能够快速查找元素的情况。
TreeSet<Type> treeSet = new TreeSet<>();
③LinkedHashSet
LinkedHashSet
是HashSet
的一个子类,它通过链表维护了元素的插入顺序。LinkedHashSet
提供O(1)
时间复杂度的插入、删除和查找操作。- 由于
LinkedHashSet
同时保留了哈希表和链表的特性,因此性能介于HashSet
和TreeSet
之间,而且能够保证元素按照插入顺序排列。 - 适用于需要保留元素插入顺序,并且具有HashSet的高性能的
LinkedHashSet<Type> linkedHashSet = new LinkedHashSet<>();
2. 相关通用方法
boolean add(E e)
: 向集合中添加指定的元素,如果集合中已经包含该元素,则返回false
。boolean contains(Object o)
: 判断集合中是否包含指定的元素。boolean remove(Object o)
: 从集合中移除指定的元素,如果集合中包含该元素,则返回true
。void clear()
: 清空集合中的所有元素。int size()
: 返回集合中的元素数量。
四、Map接口
1. 常用实现
①HashMap
HashMap
基于哈希表实现,采用数组+链表/红黑树的数据结构。HashMap
允许使用null
键和null
值,并且不保证元素的顺序。HashMap
提供O(1)
时间复杂度的插入、删除和查找操作,但在最坏情况下可能会退化到O(n)
。- 适用于需要高性能的插入、删除和查找操作,并且不关心元素顺序的情况。
HashMap<KeyType, ValueType> hashMap = new HashMap<>();
②TreeMap
TreeMap
基于红黑树(Red-Black Tree)实现,可以确保元素按照自然顺序或指定的比较器顺序进行排序。TreeMap
不允许使用null
键,但允许使用null
值。TreeMap
提供O(logn)
时间复杂度的插入、删除和查找操作。- 适用于需要保证元素顺序并能够快速查找元素的情况。
TreeMap<KeyType, ValueType> treeMap = new TreeMap<>();
③LinkedHashMap
LinkedHashMap
是HashMap
的一个子类,它通过双向链表维护了元素的插入顺序或访问顺序。LinkedHashMap
允许使用null
键和null
值,并且可以保留元素的插入顺序或访问顺序。LinkedHashMap
提供O(1)
时间复杂度的插入、删除和查找操作。- 适用于需要保留元素插入顺序或访问顺序,并且具有
HashMap
的高性能的情况。
LinkedHashMap<KeyType, ValueType> linkedHashMap = new LinkedHashMap<>();
2. 相关通用方法
V put(K key, V value)
: 将指定的键值对存储到Map
中,如果Map
中已经包含相同的键,则替换其对应的值,并返回之前的值。V get(Object key)
: 返回指定键所映射的值,如果Map
中不包含该键,则返回null
。boolean containsKey(Object key)
: 判断Map
中是否包含指定的键。boolean containsValue(Object value)
: 判断Map
中是否包含指定的值。V remove(Object key)
: 从Map
中移除指定键及其对应的值,并返回被移除的值。void clear()
: 清空Map
中的所有键值对。int size()
: 返回Map
中键值对的数量。
五、Collection接口的遍历元素方式
1. 使用Iterator(迭代器)
Iterator
对象称为迭代器,主要用于遍历Collection
集合中的元素。- 所有实现了
Collection
接口的集合类都有一个iterator()
方法,用以返回一个实现了lterator
接口的对象,即可以返回一个选代器。 lterator
仅用于遍历集合,lterator
本身并不存放对象。
采用 ctrl + j 选择itit可以快速生成
import java.util.ArrayList;
import java.util.Iterator;
public class test1 {
public static void main(String[] args) {
ArrayList<Integer> nums = new ArrayList<>();
for (int i = 0; i < 10; ++i)
nums.add(i + 1);
Iterator it = nums.iterator();
while (it.hasNext()) {
System.out.print(it.next() + " ");
}
}
}
iterator迭代器遍历完对应集合后,指向最后的元素。如果需要再次使用,需要重新重置迭代器。
2. for 循环增强(基于范围)
for (elementType element : collection) {
// 在此处处理每个元素
}
elementType
是集合中元素的类型。collection
是要遍历的集合或数组。element
是一个变量,用于迭代遍历集合中的每个元素。
六、Map接口的遍历元素方式
1. keySet()方法
取出所有 keys
,用 Set
接收。
HashMap<String, Integer> hash = new HashMap<>();
hash.put("A", 90);
hash.put("B", 80);
hash.put("C", 70);
hash.put("D", 60);
hash.put("F", 50);
Set keyset = hash.keySet();
//(1) 增强 for
System.out.println("-----第一种方式-------");
for (Object key : keyset) {
System.out.println(key + "-" + hash.get(key));
}
//(2) 迭代器
System.out.println("----第二种方式--------");
Iterator iterator = keyset.iterator();
while (iterator.hasNext()) {
Object key = iterator.next();
System.out.println(key + "-" + hash.get(key));
}
2. values()方法
取出所有 values
,用集合 Collection
接收。
HashMap<String, Integer> hash = new HashMap<>();
hash.put("A", 90);
hash.put("B", 80);
hash.put("C", 70);
hash.put("D", 60);
hash.put("F", 50);
Collection values = hash.values();
//这里可以使用所有的 Collections 使用的遍历方法
//(1) 增强 for
System.out.println("---取出所有的 value 增强 for----");
for (Object value : values) {
System.out.println(value);
}
//(2) 迭代器
System.out.println("---取出所有的 value 迭代器----");
Iterator iterator2 = values.iterator();
while (iterator2.hasNext()) {
Object value = iterator2.next();
System.out.println(value);
}
3. entrySet()方法
HashMap<String, Integer> hash = new HashMap<>();
hash.put("A", 90);
hash.put("B", 80);
hash.put("C", 70);
hash.put("D", 60);
hash.put("F", 50);
Set entrySet = hash.entrySet();// EntrySet<Map.Entry<K,V>>
//(1) 增强 for
System.out.println("----使用 EntrySet 的 for 增强(第 3 种)----");
for (Object entry : entrySet) {
//将 entry 转成 Map.Entry
Map.Entry m = (Map.Entry) entry;
System.out.println(m.getKey() + "-" + m.getValue());
}
//(2) 迭代器
System.out.println("----使用 EntrySet 的 迭代器(第 4 种)----");
Iterator iterator3 = entrySet.iterator();
while (iterator3.hasNext()) {
Object entry = iterator3.next();
//System.out.println(next.getClass());//HashMap$Node -实现-> Map.Entry (getKey,getValue)
//向下转型 Map.Entry
Map.Entry m = (Map.Entry) entry;
System.out.println(m.getKey() + "-" + m.getValue());
}