Java提供了多种集合框架类,每种都有不同的特性和用途。以下是Java中常见的集合类:
1、List(列表):
ArrayList
ArrayList 是 Java 集合框架中的一个常用类,实现了动态数组的数据结构。与传统的数组相比,ArrayList 具有动态调整大小的能力,可以方便地进行元素的添加、删除和访问。以下是关于 ArrayList 的介绍和使用方法:
特点:
1、动态数组: ArrayList 是基于动态数组的实现,可以动态地增加或减少元素的数量。
2、随机访问: 通过索引可以快速随机访问列表中的元素。
3、自动扩容: 当元素数量超过当前容量时,ArrayList 会自动扩展容量以适应更多的元素。
4、支持泛型: ArrayList 支持泛型,可以存储任意类型的对象。
基本使用:
1、创建 ArrayList 对象:
java
import java.util.ArrayList;
// 创建一个空的 ArrayList
ArrayList<String> arrayList = new ArrayList<>();
// 创建带有初始容量的 ArrayList
ArrayList<Integer> intList = new ArrayList<>(10);
2、添加元素:
java
arrayList.add("Java");
arrayList.add("Python");
arrayList.add("C++");
3、访问元素:
java
String firstElement = arrayList.get(0);
System.out.println("First Element: " + firstElement);
4、删除元素:
java
arrayList.remove("Python");
5、迭代 ArrayList:
java
for (String element : arrayList) {
System.out.println(element);
}
6、获取 ArrayList 的大小:
java
int size = arrayList.size();
System.out.println("Size: " + size);
注意事项:
1、ArrayList 是非同步的,不适合在多线程环境中使用。如果需要在多线程环境中使用,可以考虑使用 Vector 或者使用 Collections.synchronizedList 方法使 ArrayList 变为同步的。
2、如果需要在中间插入或删除元素频繁的场景,可能会使用 LinkedList 更为高效。
ArrayList 是 Java 集合框架中最常用的类之一,适用于许多不同的应用场景,从简单的列表到更复杂的数据结构。
LinkedList
LinkedList 是 Java 集合框架中的一个类,它实现了双向链表的数据结构。与 ArrayList 不同,LinkedList 不是基于动态数组实现的,而是通过节点之间的链接来组织元素。以下是关于 LinkedList 的介绍和使用方法:
特点:
1、双向链表: 每个节点包含数据元素和对前后节点的引用,使得在链表中可以双向遍历。
2、动态插入和删除: 由于链表的结构,LinkedList 在中间插入或删除元素的操作比 ArrayList 更为高效。
3、非同步: LinkedList 不是同步的,不适合在多线程环境中直接使用。在多线程环境中,可以使用 Collections.synchronizedList 方法包装它,或者考虑使用 LinkedBlockingDeque 等并发集合。
基本使用:
1、创建 LinkedList 对象:
java
import java.util.LinkedList;
// 创建一个空的 LinkedList
LinkedList<String> linkedList = new LinkedList<>();
2、添加元素:
java
linkedList.add("Java");
linkedList.add("Python");
linkedList.add("C++");
3、在指定位置插入元素:
java
linkedList.add(1, "JavaScript");
4、访问元素:
java
String firstElement = linkedList.getFirst();
System.out.println("First Element: " + firstElement);
5、删除元素:
java
linkedList.remove("Python");
6、迭代 LinkedList:
java
for (String element : linkedList) {
System.out.println(element);
}
7、获取 LinkedList 的大小:
java
int size = linkedList.size();
System.out.println("Size: " + size);
8、使用迭代器逆向遍历:
java
ListIterator<String> iterator = linkedList.listIterator(linkedList.size());
while (iterator.hasPrevious()) {
String element = iterator.previous();
System.out.println(element);
}
注意事项:
1、LinkedList 在需要频繁插入、删除元素或双向遍历的场景中表现更为出色。
2、如果对元素的随机访问较多,可以考虑使用 ArrayList。
3、在大多数情况下,考虑使用 List 接口来声明变量,以便可以更轻松地更改底层实现。例如:
java
List<String> list = new LinkedList<>(); // 或者 List<String> list = new ArrayList<>();
LinkedList 在某些特定的应用场景下非常有用,但在其他场景中可能不如 ArrayList 效率高。
选择使用哪个取决于你的具体需求和对性能的要求。
Vector
Vector 是 Java 集合框架中的一个传统类,它实现了动态数组的数据结构,与 ArrayList 类似。然而,与 ArrayList 不同的是,Vector 是同步的,因此其方法都是线程安全的。以下是关于 Vector 的介绍和使用方法:
特点:
1、同步性: Vector 是同步的,这意味着它的方法都是线程安全的。在多线程环境中,可以确保多个线程不会同时修改 Vector 对象。
2、动态数组: Vector 是基于动态数组的数据结构,可以动态地增加或减少元素的数量。
3、初始容量和增长因子: Vector 可以在创建时指定初始容量,它还具有一个增长因子,用于在需要时自动增加容量。
基本使用:
1、创建 Vector 对象:
java
import java.util.Vector;
// 创建一个空的 Vector
Vector<String> vector = new Vector<>();
// 创建指定初始容量的 Vector
Vector<Integer> intVector = new Vector<>(10);
2、添加元素:
java
vector.add("Java");
vector.add("Python");
vector.add("C++");
3、访问元素:
java
String firstElement = vector.get(0);
System.out.println("First Element: " + firstElement);
4、删除元素:
java
vector.remove("Python");
5、迭代 Vector:
java
for (String element : vector) {
System.out.println(element);
}
6、获取 Vector 的大小和容量:
java
int size = vector.size();
int capacity = vector.capacity();
System.out.println("Size: " + size);
System.out.println("Capacity: " + capacity);
7、同步访问:
由于 Vector 是同步的,可以在多线程环境中安全使用,但在单线程环境下使用 ArrayList 可能更高效。
注意事项:
1、由于同步的开销,除非需要线程安全,否则建议使用 ArrayList 或者其他非同步的集合类。
2、如果需要在中间插入或删除元素频繁的场景,可能会使用 LinkedList 更为高效。
总的来说,Vector 在现代 Java 开发中不常用,因为它的同步性能开销相对较高,而且有更现代的替代品,如 ArrayList 和 LinkedList,它们在大多数情况下更为常见和高效。
Stack
Stack 是 Java 集合框架中的一个类,它实现了后进先出(LIFO)的堆栈数据结构。Stack 继承自 Vector 类,因此它保留了 Vector 的同步性,但由于其特定的用途,通常建议使用更现代的 Deque 接口的实现类 LinkedList 代替 Stack。以下是关于 Stack 的介绍和使用方法:
特点:
1、后进先出(LIFO): Stack 是一种后进先出的数据结构,即最后添加的元素最先被移除。
2、继承自 Vector: Stack 类继承自 Vector,因此具有 Vector 的同步性。
基本使用:
1、创建 Stack 对象:
java
import java.util.Stack;
// 创建一个空的 Stack
Stack<String> stack = new Stack<>();
2、压栈和弹栈:
java
stack.push("Java");
stack.push("Python");
stack.push("C++");
// 弹出栈顶元素
String topElement = stack.pop();
System.out.println("Top Element: " + topElement);
3、查看栈顶元素:
java
String peekElement = stack.peek();
System.out.println("Top Element (without removing): " + peekElement);
4、判断栈是否为空:
java
boolean isEmpty = stack.isEmpty();
System.out.println("Is Stack Empty? " + isEmpty);
5、获取栈的大小:
java
int size = stack.size();
System.out.println("Stack Size: " + size);
注意事项:
1、Stack 的同步性使得在多线程环境中可以安全使用,但如果不需要同步,推荐使用 LinkedList 作为栈的替代品。
2、在现代 Java 编程中,更常用的做法是使用 Deque 接口的实现类 LinkedList 来实现栈的功能,因为它提供了更多灵活性和性能。
下面是使用 LinkedList 实现栈的示例:
java
import java.util.LinkedList;
// 创建一个空的栈
LinkedList<String> stack = new LinkedList<>();
// 压栈
stack.push("Java");
stack.push("Python");
stack.push("C++");
// 弹栈
String topElement = stack.pop();
System.out.println("Top Element: " + topElement);
总体而言,在现代 Java 编程中,推荐使用 Deque 接口的实现类 LinkedList 或者 ArrayDeque 来实现栈的功能。
2、Set(集合):
HashSet
HashSet 是 Java 集合框架中的一个类,它实现了 Set 接口,基于哈希表实现。以下是关于 HashSet 的介绍和使用方法:
特点:
1、无序性: HashSet 不保证元素的顺序,即你添加元素的顺序不一定就是元素被存储的顺序。
2、唯一性: HashSet 中不能包含重复的元素。如果尝试将重复的元素添加到 HashSet 中,添加操作将被忽略。
3、基于哈希表: HashSet 使用哈希表来存储元素,因此具有快速的查找性能。
基本使用:
1、创建 HashSet 对象:
java
import java.util.HashSet;
// 创建一个空的 HashSet
HashSet<String> hashSet = new HashSet<>();
2、添加元素:
java
hashSet.add("Java");
hashSet.add("Python");
hashSet.add("C++");
3、判断元素是否存在:
java
boolean containsJava = hashSet.contains("Java");
System.out.println("Contains Java? " + containsJava);
4、删除元素:
java
hashSet.remove("Python");
5、获取 HashSet 的大小:
java
int size = hashSet.size();
System.out.println("HashSet Size: " + size);
6、迭代 HashSet:
java
for (String element : hashSet) {
System.out.println(element);
}
注意事项:
1、由于 HashSet 是基于哈希表实现的,元素的存储顺序是不确定的。如果需要有序性,可以考虑使用 LinkedHashSet。
2、HashSet 对元素的唯一性的判断是通过元素的 hashCode 和 equals 方法来完成的。因此,如果你在自定义类中使用 HashSet,确保正确实现了 hashCode 和 equals 方法。
3、HashSet 不是同步的,如果需要在多线程环境中使用,可以考虑使用 Collections.synchronizedSet 方法包装它,或者使用 ConcurrentHashSet。
HashSet 是在很多场景下都很有用的集合类,特别是在需要快速查找不重复元素的情况下。
LinkedHashSet
LinkedHashSet 是 Java 集合框架中的一个类,它是 HashSet 的一个子类,实现了 Set 接口。与 HashSet 不同的是,LinkedHashSet 维护元素的插入顺序,因此它提供了有序性。以下是关于 LinkedHashSet 的介绍和使用方法:
特点:
1、有序性: LinkedHashSet 会按照元素的插入顺序维护元素的顺序。因此,迭代 LinkedHashSet 时会按照插入的顺序返回元素。
2、唯一性: 与 HashSet 类似,LinkedHashSet 中不能包含重复的元素。
基本使用:
1、创建 LinkedHashSet 对象:
java
import java.util.LinkedHashSet;
// 创建一个空的 LinkedHashSet
LinkedHashSet<String> linkedHashSet = new LinkedHashSet<>();
2、添加元素:
java
linkedHashSet.add("Java");
linkedHashSet.add("Python");
linkedHashSet.add("C++");
3、判断元素是否存在:
java
boolean containsJava = linkedHashSet.contains("Java");
System.out.println("Contains Java? " + containsJava);
4、删除元素:
java
linkedHashSet.remove("Python");
5、获取 LinkedHashSet 的大小:
java
int size = linkedHashSet.size();
System.out.println("LinkedHashSet Size: " + size);
6、迭代 LinkedHashSet:
java
for (String element : linkedHashSet) {
System.out.println(element);
}
注意事项:
1、LinkedHashSet 维护插入顺序的特性使得它适用于需要按照元素插入的顺序进行迭代的场景。
2、LinkedHashSet 不是同步的,如果需要在多线程环境中使用,可以考虑使用 Collections.synchronizedSet 方法包装它,或者使用 ConcurrentLinkedHashSet。
总体而言,LinkedHashSet 是在需要按照插入顺序保持元素的场景中很有用的集合类。
TreeSet
TreeSet 是 Java 集合框架中的一个类,它实现了 SortedSet 接口,是基于红黑树(Red-Black Tree)实现的有序集合。以下是关于 TreeSet 的介绍和使用方法:
特点:
1、有序性: TreeSet 会按照元素的自然顺序或者通过提供的比较器(Comparator)进行排序。
因此,迭代 TreeSet 时会按照升序顺序返回元素。
2、唯一性: 与 Set 接口相同,TreeSet 中不能包含重复的元素。
基本使用:
1、创建 TreeSet 对象:
java
import java.util.TreeSet;
// 创建一个空的 TreeSet
TreeSet<String> treeSet = new TreeSet<>();
2、添加元素:
java
treeSet.add("Java");
treeSet.add("Python");
treeSet.add("C++");
3、判断元素是否存在:
java
boolean containsJava = treeSet.contains("Java");
System.out.println("Contains Java? " + containsJava);
4、删除元素:
java
treeSet.remove("Python");
5、获取 TreeSet 的大小:
java
int size = treeSet.size();
System.out.println("TreeSet Size: " + size);
6、迭代 TreeSet:
java
for (String element : treeSet) {
System.out.println(element);
}
自定义排序:
TreeSet 可以通过提供一个比较器(Comparator)来实现自定义排序。例如,如果要按照字符串长度降序排序,可以创建一个比较器并传递给 TreeSet 的构造函数:
java
import java.util.TreeSet;
import java.util.Comparator;
public class CustomComparatorExample {
public static void main(String[] args) {
// 创建一个基于字符串长度的降序排序的 TreeSet
TreeSet<String> customTreeSet = new TreeSet<>(Comparator.comparing(String::length).reversed());
// 添加元素
customTreeSet.add("Java");
customTreeSet.add("Python");
customTreeSet.add("C++");
// 迭代 TreeSet
for (String element : customTreeSet) {
System.out.println(element);
}
}
}
注意事项:
1、如果元素是自定义类的对象,确保该类实现了 Comparable 接口或者在创建 TreeSet 时提供了比较器,以便 TreeSet 知道如何对元素进行排序。
2、TreeSet 的排序是基于元素的自然顺序或者提供的比较器,因此元素类型必须是可比较的。
3、TreeSet 不是同步的,如果需要在多线程环境中使用,可以考虑使用 Collections.synchronizedSortedSet 方法包装它,或者使用 ConcurrentSkipListSet。
TreeSet 在需要有序集合的场景中非常有用,尤其是当你需要按照自然顺序或者自定义的顺序迭代元素时。
3、Map(映射):
HashMap
HashMap 是 Java 集合框架中的一个类,它实现了 Map 接口,用于存储键值对。以下是关于 HashMap 的介绍和使用方法:
特点:
1、键值对存储: HashMap 存储的是键值对(key-value pair),每个键都映射到一个值。
2、无序性: HashMap 中的键值对没有固定的顺序,即你添加键值对的顺序不一定就是它们被存储的顺序。
3、唯一性: HashMap 中的键是唯一的,一个键只能对应一个值。但值可以重复。
4、基于哈希表: HashMap 使用哈希表实现,通过键的哈希码来快速定位键值对的存储位置,从而实现高效的查找、插入和删除操作。
基本使用:
1、创建 HashMap 对象:
java
import java.util.HashMap;
import java.util.Map;
// 创建一个空的 HashMap
HashMap<String, Integer> hashMap = new HashMap<>();
2、添加键值对:
java
hashMap.put("Java", 1);
hashMap.put("Python", 2);
hashMap.put("C++", 3);
3、获取值:
java
int javaValue = hashMap.get("Java");
System.out.println("Java's value is: " + javaValue);
4、判断键是否存在:
java
boolean containsJava = hashMap.containsKey("Java");
System.out.println("Contains Java? " + containsJava);
5、删除键值对:
java
hashMap.remove("Python");
6、获取 HashMap 的大小:
java
int size = hashMap.size();
System.out.println("HashMap Size: " + size);
7、迭代 HashMap:
java
for (Map.Entry<String, Integer> entry : hashMap.entrySet()) {
System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue());
}
注意事项:
1、HashMap 不是同步的,如果需要在多线程环境中使用,可以考虑使用 Collections.synchronizedMap 方法包装它,或者使用 ConcurrentHashMap。
2、由于 HashMap 中的键值对没有固定的顺序,如果需要有序性,可以考虑使用 LinkedHashMap。
总体而言,HashMap 是在很多场景下都非常有用的集合类,特别是在需要键值对存储和快速查找的情况下。
LinkedHashMap
LinkedHashMap 是 Java 集合框架中的一个类,它实现了 Map 接口,是 HashMap 的一个具体实现。与 HashMap 不同的是,LinkedHashMap 在内部使用双向链表维护插入顺序或者访问顺序,使得它可以保留元素的插入顺序或者访问顺序。以下是关于 LinkedHashMap 的介绍和使用方法:
特点:
1、有序性: LinkedHashMap 可以保留元素的插入顺序或者访问顺序。通过构造函数可以选择使用插入顺序或者访问顺序。
2、基于哈希表和链表: LinkedHashMap 内部使用哈希表来存储键值对,并通过双向链表来维护元素的顺序。
3、性能: 与 HashMap 类似,LinkedHashMap 具有快速的查找性能,但相对于 HashMap,在迭代时元素的顺序是有序的。
基本使用:
1、创建 LinkedHashMap 对象:
java
import java.util.LinkedHashMap;
import java.util.Map;
// 创建一个空的 LinkedHashMap,按照插入顺序
LinkedHashMap<String, Integer> linkedHashMap = new LinkedHashMap<>();
2、添加键值对:
java
linkedHashMap.put("Java", 1);
linkedHashMap.put("Python", 2);
linkedHashMap.put("C++", 3);
3、获取值:
java
int javaValue = linkedHashMap.get("Java");
System.out.println("Java's value is: " + javaValue);
4、判断键是否存在:
java
boolean containsJava = linkedHashMap.containsKey("Java");
System.out.println("Contains Java? " + containsJava);
5、删除键值对:
java
linkedHashMap.remove("Python");
6、获取 LinkedHashMap 的大小:
java
int size = linkedHashMap.size();
System.out.println("LinkedHashMap Size: " + size);
7、迭代 LinkedHashMap:
java
for (Map.Entry<String, Integer> entry : linkedHashMap.entrySet()) {
System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue());
}
构造函数选择顺序:
1、LinkedHashMap 的构造函数允许你选择使用插入顺序或者访问顺序。默认情况下是按照插入顺序:
java
LinkedHashMap<K, V> linkedHashMap = new LinkedHashMap<>();
2、如果需要按照访问顺序:
java
LinkedHashMap<K, V> linkedHashMap = new LinkedHashMap<>(16, 0.75f, true);
上述构造函数的第三个参数设置为 true 表示按照访问顺序。当使用 get 方法访问某个键时,该键会被移到双向链表的末尾,保持最近访问的元素在链表尾部。
总体而言,LinkedHashMap 在需要保留元素插入顺序或者访问顺序的场景中非常有用。如果你需要在迭代时保持元素的有序性,可以选择使用 LinkedHashMap。
TreeMap
TreeMap 是 Java 集合框架中的一个类,它实现了 SortedMap 接口,是基于红黑树(Red-Black Tree)实现的有序映射。以下是关于 TreeMap 的介绍和使用方法:
特点:
1、有序性: TreeMap 中的键值对是按照键的自然顺序或者通过提供的比较器进行排序的。因此,迭代 TreeMap 时会按照升序顺序返回键值对。
2、唯一性: 与 Map 接口相同,TreeMap 中的键是唯一的,一个键只能对应一个值。
3、基于红黑树: TreeMap 内部使用红黑树数据结构,这是一种自平衡的二叉查找树。这使得 TreeMap 具有较好的查找、插入和删除性能。
基本使用:
1、创建 TreeMap 对象:
java
import java.util.TreeMap;
// 创建一个空的 TreeMap
TreeMap<String, Integer> treeMap = new TreeMap<>();
2、添加键值对:
java
treeMap.put("Java", 1);
treeMap.put("Python", 2);
treeMap.put("C++", 3);
3、获取值:
java
int javaValue = treeMap.get("Java");
System.out.println("Java's value is: " + javaValue);
4、判断键是否存在:
java
boolean containsJava = treeMap.containsKey("Java");
System.out.println("Contains Java? " + containsJava);
5、删除键值对:
java
treeMap.remove("Python");
6、获取 TreeMap 的大小:
java
int size = treeMap.size();
System.out.println("TreeMap Size: " + size);
7、迭代 TreeMap:
java
for (String key : treeMap.keySet()) {
System.out.println("Key: " + key + ", Value: " + treeMap.get(key));
}
自定义排序:
TreeMap 允许在创建时提供一个比较器(Comparator),以便进行自定义排序。例如,如果要按照字符串长度降序排序:
java
import java.util.TreeMap;
import java.util.Comparator;
public class CustomComparatorExample {
public static void main(String[] args) {
// 创建一个基于字符串长度的降序排序的 TreeMap
TreeMap<String, Integer> customTreeMap = new TreeMap<>(Comparator.comparing(String::length).reversed());
// 添加键值对
customTreeMap.put("Java", 1);
customTreeMap.put("Python", 2);
customTreeMap.put("C++", 3);
// 迭代 TreeMap
for (String key : customTreeMap.keySet()) {
System.out.println("Key: " + key + ", Value: " + customTreeMap.get(key));
}
}
}
注意事项:
1、如果元素是自定义类的对象,确保该类实现了 Comparable 接口或者在创建 TreeMap 时提供了比较器,以便 TreeMap 知道如何对元素进行排序。
2、TreeMap 的排序是基于键的自然顺序或者提供的比较器,因此键的类型必须是可比较的。
3、TreeMap 不是同步的,如果需要在多线程环境中使用,可以考虑使用 Collections.synchronizedSortedMap 方法包装它,或者使用 ConcurrentSkipListMap。
TreeMap 在需要有序映射的场景中非常有用,尤其是当你需要按照自然顺序或者自定义顺序迭代键值对时。
HashTable
HashTable 是 Java 集合框架中的一个类,它实现了 Map 接口,提供了键值对的存储和检索。HashTable 是早期的 Java 集合实现之一,但在 Java Collections Framework 中已经被更先进的 HashMap 取代。尽管如此,了解 HashTable 仍然有其价值。
特点:
1、同步性: HashTable 是线程安全的,所有的方法都是同步的。这是通过在每个方法上添加 synchronized 关键字来实现的。因此,多个线程可以安全地同时访问 HashTable。
2、不允许空键或空值: HashTable 不允许空键(key)或空值(value),如果尝试插入空键或空值,会抛出 NullPointerException。
3、基于拉链法的哈希表: HashTable 内部使用拉链法来解决哈希冲突,即在哈希表的每个位置上维护一个链表。
基本使用:
1、创建 HashTable 对象:
java
import java.util.Hashtable;
import java.util.Map;
// 创建一个空的 HashTable
Hashtable<String, Integer> hashTable = new Hashtable<>();
2、添加键值对:
java
hashTable.put("Java", 1);
hashTable.put("Python", 2);
hashTable.put("C++", 3);
3、获取值:
java
int javaValue = hashTable.get("Java");
System.out.println("Java's value is: " + javaValue);
4、判断键是否存在:
java
boolean containsJava = hashTable.containsKey("Java");
System.out.println("Contains Java? " + containsJava);
5、删除键值对:
java
hashTable.remove("Python");
6、获取 HashTable 的大小:
java
int size = hashTable.size();
System.out.println("HashTable Size: " + size);
7、迭代 HashTable:
java
for (Map.Entry<String, Integer> entry : hashTable.entrySet()) {
System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue());
}
注意事项:
1、HashTable 是线程安全的,但在多线程环境下使用可能会导致性能问题,因为所有的方法都是同步的。在现代的 Java 中,通常推荐使用 HashMap 代替 HashTable,后者的同步性能开销较大。
2、HashTable 不允许空键或空值,如果需要支持空键或空值,可以考虑使用 HashMap。
3、考虑到 HashTable 的性能和一些限制,通常更推荐使用 HashMap 或者 ConcurrentHashMap,它们提供了更好的性能和更丰富的功能。
尽管 HashTable 不再是首选的集合实现,了解它的特点对于理解 Java 集合框架的演变和一些基本的同步概念仍然有帮助。
4、Queue(队列):
PriorityQueue
PriorityQueue 是 Java 集合框架中的一个类,它实现了一个优先级队列(priority queue)。优先级队列是一种特殊的队列,其中的元素按照其优先级进行排序。在 PriorityQueue 中,优先级由元素的比较器或元素自身的自然顺序决定。以下是关于 PriorityQueue 的介绍和使用方法:
特点:
1、优先级排序: PriorityQueue 维护了一个基于堆的完全二叉树,树中的每个节点表示队列中的一个元素。元素按照其优先级排列,根节点具有最高优先级。
2、堆实现: 在默认情况下,PriorityQueue 是一个最小堆(Min Heap)。可以通过提供自定义的比较器来创建最大堆(Max Heap)。
基本使用:
1、创建 PriorityQueue 对象:
java
import java.util.PriorityQueue;
// 创建一个默认的最小堆 PriorityQueue
PriorityQueue<Integer> minHeap = new PriorityQueue<>();
2、添加元素:
java
minHeap.add(5);
minHeap.add(3);
minHeap.add(8);
3、获取并移除队列头部的元素:
java
int head = minHeap.poll();
System.out.println("Head of the minHeap: " + head);
4、获取但不移除队列头部的元素:
java
int peek = minHeap.peek();
System.out.println("Peek of the minHeap: " + peek);
5、自定义比较器:
java
import java.util.PriorityQueue;
import java.util.Comparator;
// 创建一个最大堆 PriorityQueue,提供自定义比较器
PriorityQueue<Integer> maxHeap = new PriorityQueue<>(Comparator.reverseOrder());
自定义对象的比较:
如果要在 PriorityQueue 中存储自定义对象,确保对象实现了 Comparable 接口或者在创建 PriorityQueue 时提供了比较器。
java
import java.util.PriorityQueue;
public class CustomObjectExample {
public static void main(String[] args) {
// 创建一个 Priority Queue 存储自定义对象
PriorityQueue<Person> personQueue = new PriorityQueue<>();
// 添加 Person 对象
personQueue.add(new Person("Alice", 25));
personQueue.add(new Person("Bob", 30));
personQueue.add(new Person("Charlie", 22));
// 获取并移除头部的 Person 对象
Person headPerson = personQueue.poll();
System.out.println("Head of the personQueue: " + headPerson.getName() + ", Age: " + headPerson.getAge());
}
}
class Person implements Comparable<Person> {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
@Override
public int compareTo(Person other) {
// 按照年龄升序排序
return Integer.compare(this.age, other.age);
}
}
在上述示例中,Person 类实现了 Comparable 接口,并在 compareTo 方法中定义了对象之间的比较规则。这使得 Person 对象可以按照年龄升序排序。
LinkedList
略...
ArrayDeque
ArrayDeque 是 Java 集合框架中的一个双端队列(double-ended queue)。它实现了 Deque 接口,提供了对队列两端进行高效操作的方法。以下是关于 ArrayDeque 的介绍和使用方法:
特点:
1、底层数据结构: ArrayDeque 使用可调整大小的数组作为其底层数据结构,可以根据需要动态调整数组的大小。
2、双端队列: ArrayDeque 是一个双端队列,允许在队列的两端进行添加(push)和移除(pop)操作。它还支持在队列的头部和尾部进行插入和删除操作。
3、不限制容量: 与传统的队列不同,ArrayDeque 不限制容量。它可以根据需要动态调整大小,因此在实际使用中无需关心容量问题。
基本使用:
1、创建 ArrayDeque 对象:
java
import java.util.ArrayDeque;
// 创建一个空的 ArrayDeque
ArrayDeque<String> arrayDeque = new ArrayDeque<>();
2、添加元素:
在队列尾部添加元素:
java
arrayDeque.add("Element1");
arrayDeque.add("Element2");
在队列头部添加元素:
java
arrayDeque.addFirst("FirstElement");
在队列尾部添加元素:
java
arrayDeque.addLast("LastElement");
3、获取并移除元素:
从队列头部获取并移除元素:
java
String firstElement = arrayDeque.pollFirst();
从队列尾部获取并移除元素:
java
String lastElement = arrayDeque.pollLast();
4、获取但不移除元素:
获取队列头部的元素(不移除):
java
String peekFirstElement = arrayDeque.peekFirst();
获取队列尾部的元素(不移除):
java
String peekLastElement = arrayDeque.peekLast();
应用场景:
1、双端队列操作: 当需要在队列两端执行高效的插入、删除和获取元素操作时,ArrayDeque 是一个很好的选择。
2、无限容量队列: ArrayDeque 不限制容量,因此适用于需要不断添加元素而无需担心容量问题的情况。
3、栈的实现: 由于 ArrayDeque 具有栈的特性,可以用它来实现栈的功能。使用 addFirst 和 pollFirst 方法可以模拟栈的操作。
java
ArrayDeque<Integer> stack = new ArrayDeque<>();
stack.addFirst(1); // 入栈
int topElement = stack.pollFirst(); // 出栈
ArrayDeque 提供了一种灵活而高效的双端队列实现,适用于多种场景。它是 Deque 接口的一个实现,因此具备队列和栈的特性。在选择集合类时,根据具体的需求和操作模式选择适当的实现类是很重要的。
5、Deque(双端队列):
ArrayDeque
略...
LinkedList
略...
6、Collection(集合接口):
List
略...
Set
略...
Queue
略...
7、Concurrent集合:
ConcurrentHashMap
ConcurrentHashMap 是 Java 集合框架中的一个线程安全的哈希表实现,它继承自 HashMap 类,实现了 ConcurrentMap 接口。相比于 HashMap,ConcurrentHashMap 提供了更高的并发性,特别适用于多线程环境。以下是关于 ConcurrentHashMap 的介绍和使用方法:
特点和优势:
1、线程安全性: ConcurrentHashMap 是线程安全的,多个线程可以同时读取和写入而不会导致数据不一致。
2、分段锁: ConcurrentHashMap 使用了分段锁机制,将整个数据集分成多个段(Segment),每个段相当于一个小的 HashMap,不同的段可以独立进行读写操作,提高并发性能。
3、高并发读: 由于读操作并不会涉及到锁,所以多个线程可以同时读取。
4、低并发写: 写操作只涉及到段级别的锁,多个线程可以同时写入不同的段,从而提高写入操作的并发性。
基本用法:
1、创建 ConcurrentHashMap 对象:
java
import java.util.concurrent.ConcurrentHashMap;
import java.util.Map;
// 创建一个 ConcurrentHashMap
Map<String, Integer> concurrentHashMap = new ConcurrentHashMap<>();
2、添加元素:
java
concurrentHashMap.put("Key1", 1);
concurrentHashMap.put("Key2", 2);
3、获取元素:
java
int value = concurrentHashMap.get("Key1");
4、删除元素:
java
concurrentHashMap.remove("Key2");
5、遍历元素:
java
for (Map.Entry<String, Integer> entry : concurrentHashMap.entrySet()) {
System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue());
}
6、其他操作:
ConcurrentHashMap 还提供了一些其他方法,如 putIfAbsent、replace 等,用于更复杂的操作。
应用场景:
1、高并发读写: 当需要在多线程环境下进行高并发的读写操作时,ConcurrentHashMap 是一个很好的选择。
2、分布式场景: 由于 ConcurrentHashMap 的分段锁机制,它在分布式场景中也能够提供较好的性能。
在并发环境中,ConcurrentHashMap 是一个非常有用的工具,可以有效地提高多线程环境下的性能和并发控制。
ConcurrentLinkedQueue
ConcurrentLinkedQueue 是 Java 集合框架中的一个线程安全的队列实现,它实现了 Queue 接口。它的设计目标是在多线程环境中提供高效的并发操作。以下是关于 ConcurrentLinkedQueue 的介绍和使用方法:
特点和优势:
1、线程安全性: ConcurrentLinkedQueue 是线程安全的,支持并发读写操作,无需额外的同步。
2、基于非阻塞算法: ConcurrentLinkedQueue 的实现基于非阻塞算法,采用一种称为 "Michael and Scott" 的无锁算法,不使用锁来保护共享数据,而是使用 CAS(Compare And Swap)操作。
3、高并发性: 在多线程环境中,ConcurrentLinkedQueue 提供了高效的并发性能,特别适用于高并发读写的场景。
基本用法:
1、创建 ConcurrentLinkedQueue 对象:
java
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
// 创建一个 ConcurrentLinkedQueue
Queue<String> concurrentLinkedQueue = new ConcurrentLinkedQueue<>();
2、添加元素:
java
concurrentLinkedQueue.offer("Element1");
concurrentLinkedQueue.offer("Element2");
3、获取并移除元素:
java
String element = concurrentLinkedQueue.poll();
4、获取但不移除元素:
java
String peekedElement = concurrentLinkedQueue.peek();
5、遍历元素:
java
for (String element : concurrentLinkedQueue) {
System.out.println(element);
}
6、获取队列大小:
java
int size = concurrentLinkedQueue.size();
7、其他操作:
ConcurrentLinkedQueue 还提供了一些其他方法,如 remove、contains 等,用于更复杂的操作。
应用场景:
1、生产者-消费者模式: ConcurrentLinkedQueue 可以用于实现生产者-消费者模式,其中多个线程可以安全地在队列中添加和获取元素。
2、无界队列: ConcurrentLinkedQueue 是一个无界队列,适用于需要不断添加元素而无需担心容量问题的场景。
3、高并发读写: 当需要在多线程环境中进行高并发读写操作时,ConcurrentLinkedQueue 是一个很好的选择。
在多线程环境中,ConcurrentLinkedQueue 提供了一种高效的队列实现,特别适用于需要高并发性能的场景。
ConcurrentSkipListMap
ConcurrentSkipListMap 是 Java 集合框架中的一个线程安全的、有序的 Map 实现,它实现了 ConcurrentNavigableMap 接口。ConcurrentSkipListMap 基于跳跃表(Skip List)数据结构,提供了高效的并发访问能力。以下是关于 ConcurrentSkipListMap 的介绍和使用方法:
特点和优势:
1、线程安全性: ConcurrentSkipListMap 是线程安全的,支持并发读写操作。
2、有序性: ConcurrentSkipListMap 的键是有序的,它们按照自然顺序或者通过比较器进行排序。
3、高并发性: 在多线程环境中,ConcurrentSkipListMap 提供了高效的并发性能,适用于高并发读写的场景。
4、支持导航操作: ConcurrentSkipListMap 实现了 ConcurrentNavigableMap 接口,提供了一系列导航方法,如 ceilingKey、floorKey 等。
基本用法:
1、创建 ConcurrentSkipListMap 对象:
java
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.Map;
// 创建一个 ConcurrentSkipListMap
Map<String, Integer> concurrentSkipListMap = new ConcurrentSkipListMap<>();
2、添加元素:
java
concurrentSkipListMap.put("Key1", 1);
concurrentSkipListMap.put("Key2", 2);
3、获取元素:
java
int value = concurrentSkipListMap.get("Key1");
4、删除元素:
java
concurrentSkipListMap.remove("Key2");
5、遍历元素:
java
for (Map.Entry<String, Integer> entry : concurrentSkipListMap.entrySet()) {
System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue());
}
6、导航操作:
java
// 获取大于等于给定键的最小键
String ceilingKey = concurrentSkipListMap.ceilingKey("Key1");
// 获取小于等于给定键的最大键
String floorKey = concurrentSkipListMap.floorKey("Key2");
7、其他操作:
ConcurrentSkipListMap 还提供了一些其他方法,如 higherKey、lowerKey 等,用于更复杂的导航操作。
应用场景:
1、有序映射: 当需要在多线程环境中维护一个有序的键值对集合时,ConcurrentSkipListMap 是一个很好的选择。
2、高并发读写: 当需要在多线程环境中进行高并发读写操作时,ConcurrentSkipListMap 是一个适用的实现。
3、导航操作: 当需要进行一些导航操作,如查找大于等于给定键的最小键等,ConcurrentSkipListMap 提供了相应的方法。
在需要有序、并发安全的键值对集合时,ConcurrentSkipListMap 提供了一种高效的实现。
CopyOnWriteArrayList
CopyOnWriteArrayList 是 Java 集合框架中的一个线程安全的 List 实现,它通过在修改操作时创建底层数组的副本来实现线程安全。这个副本用于写操作,而读操作仍然在原数组上进行。由于读写分离,CopyOnWriteArrayList 在读多写少的场景中具有较好的性能。以下是关于 CopyOnWriteArrayList 的介绍和使用方法:
特点和优势:
1、线程安全性: CopyOnWriteArrayList 是线程安全的,支持并发读写操作。
2、写时复制: 在写操作时,CopyOnWriteArrayList 会创建底层数组的副本,因此写操作不会影响正在进行的读操作。
3、适用于读多写少: 由于读写分离的特性,CopyOnWriteArrayList 在读多写少的场景中性能较好。
基本用法:
1、创建 CopyOnWriteArrayList 对象:
java
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
// 创建一个 CopyOnWriteArrayList
List<String> copyOnWriteArrayList = new CopyOnWriteArrayList<>();
2、添加元素:
java
copyOnWriteArrayList.add("Element1");
copyOnWriteArrayList.add("Element2");
3、获取元素:
java
String element = copyOnWriteArrayList.get(0);
4、删除元素:
java
copyOnWriteArrayList.remove("Element1");
5、遍历元素:
java
for (String element : copyOnWriteArrayList) {
System.out.println(element);
}
6、其他操作:
CopyOnWriteArrayList 还提供了一些其他方法,如 addAll、clear 等,用于更复杂的操作。
应用场景:
1、读多写少: CopyOnWriteArrayList 适用于读多写少的场景,其中写操作的频率较低。
2、读写分离: 当需要在多线程环境中同时进行读写操作时,CopyOnWriteArrayList 提供了一种简单而有效的线程安全解决方案。
3、不要求实时更新: 由于写操作并不会立即影响到正在进行的读操作,适用于不要求实时更新的场景。
在使用 CopyOnWriteArrayList 时,需要注意它的一些特性,如写时复制带来的内存开销,以及读取时可能看到过时的数据。因此,选择是否使用 CopyOnWriteArrayList 取决于具体的应用场景和需求。
CopyOnWriteArraySet
CopyOnWriteArraySet 是 Java 集合框架中的一个线程安全的 Set 实现,它是通过使用 CopyOnWriteArrayList 来实现的。它保证了在迭代过程中不会抛出 ConcurrentModificationException 异常,因为写操作会在新的副本上进行,而读操作则在原有的集合上进行。以下是关于 CopyOnWriteArraySet 的介绍和使用方法:
特点和优势:
1、线程安全性: CopyOnWriteArraySet 是线程安全的,支持并发读写操作。
2、写时复制: 在写操作时,CopyOnWriteArraySet 会创建底层数组的副本,因此写操作不会影响正在进行的读操作。
3、不抛异常: 在迭代过程中,即使集合发生了修改,也不会抛出 ConcurrentModificationException 异常。
基本用法:
1、创建 CopyOnWriteArraySet 对象:
java
for (String element : copyOnWriteArraySet) {
System.out.println(element);
}
java
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
// 创建一个 CopyOnWriteArraySet
Set<String> copyOnWriteArraySet = new CopyOnWriteArraySet<>();
2、添加元素:
java
copyOnWriteArraySet.add("Element1");
copyOnWriteArraySet.add("Element2");
3、删除元素:
java
copyOnWriteArraySet.remove("Element1");
4、遍历元素:
java
for (String element : copyOnWriteArraySet) {
System.out.println(element);
}
5、获取集合大小:
java
int size = copyOnWriteArraySet.size();
6、其他操作:
CopyOnWriteArraySet 还提供了一些其他方法,如 addAll、clear 等,用于更复杂的操作。
应用场景:
1、读多写少: CopyOnWriteArraySet 适用于读多写少的场景,其中写操作的频率较低。
2、读写分离: 当需要在多线程环境中同时进行读写操作时,CopyOnWriteArraySet 提供了一种简单而有效的线程安全解决方案。
3、不抛异常的迭代: 如果需要在迭代过程中不抛出 ConcurrentModificationException 异常,可以考虑使用 CopyOnWriteArraySet。
在实际使用时,需要根据业务需求和性能要求来选择合适的集合类型。
8、其他:
BitSet
BitSet 是 Java 集合框架中的一种用于位操作的集合类。它以位为单位表示集合中的元素,可以有效地存储和操作大量的位信息。主要用于处理一系列的开关状态或者标记。以下是关于 BitSet 的介绍和使用方法:
创建 BitSet 对象:
java
import java.util.BitSet;
// 创建一个 BitSet,默认大小为64位
BitSet bitSet = new BitSet();
基本操作:
1、设置位:
java
bitSet.set(2); // 将索引2处的位设置为true
2、清除位:
java
bitSet.clear(5); // 将索引5处的位设置为false
3、获取位状态:
java
boolean isSet = bitSet.get(3); // 获取索引3处的位状态
4、翻转位:
java
bitSet.flip(4); // 翻转索引4处的位,即从true变为false,或从false变为true
5、获取位数(位的总数):
java
int numberOfBits = bitSet.size(); // 获取位的总数
6、获取设置为true的位数:
java
int numberOfSetBits = bitSet.cardinality(); // 获取设置为true的位数
7、按位与、按位或、按位异或等位运算:
java
BitSet anotherBitSet = new BitSet();
anotherBitSet.set(2);
// 按位与
bitSet.and(anotherBitSet);
// 按位或
bitSet.or(anotherBitSet);
// 按位异或
bitSet.xor(anotherBitSet);
8、其他操作:
BitSet 还提供了许多其他的位操作方法,如 andNot、nextSetBit、nextClearBit 等。
应用场景:
1、位图索引: BitSet 可以用于实现位图索引,用于快速查找某个元素是否存在。
2、标记状态: 用于标记某个状态的开关,例如网络端口的占用状态、任务完成状态等。
3、压缩存储: 在一些特定场景下,BitSet 可以用于压缩存储大量的布尔型信息。
示例:
java
import java.util.BitSet;
public class BitSetExample {
public static void main(String[] args) {
BitSet bitSet = new BitSet();
// 设置位
bitSet.set(1);
bitSet.set(3);
// 获取位状态
System.out.println(bitSet.get(1)); // 输出 true
System.out.println(bitSet.get(2)); // 输出 false
// 翻转位
bitSet.flip(2);
System.out.println(bitSet.get(2)); // 输出 true
// 获取位数
System.out.println(bitSet.size()); // 输出 64
// 获取设置为true的位数
System.out.println(bitSet.cardinality()); // 输出 3
}
}
BitSet 是一个用于位操作的强大工具,特别适用于需要高效存储和操作大量位信息的场景。在使用时,根据具体的需求选择合适的位操作方法。
Properties
Properties 类是 Java 集合框架中的一个特殊的类,用于处理属性文件。它继承自 Hashtable 类,因此具备了 Hashtable 的一些特性,但主要用于管理键值对形式的配置信息。以下是关于 Properties 的介绍和使用方法:
创建 Properties 对象:
java
import java.util.Properties;
// 创建一个 Properties 对象
Properties properties = new Properties();
添加和获取属性:
1、添加属性:
java
// 添加属性
properties.setProperty("key1", "value1");
properties.setProperty("key2", "value2");
2、获取属性:
java
// 获取属性值
String value = properties.getProperty("key1");
System.out.println(value); // 输出 "value1"
3、读取和写入属性文件:
从文件读取属性:
java
import java.io.FileInputStream;
import java.io.IOException;
// 从文件读取属性
try (FileInputStream input = new FileInputStream("config.properties")) {
properties.load(input);
} catch (IOException e) {
e.printStackTrace();
}
将属性写入文件:
java
import java.io.FileOutputStream;
import java.io.IOException;
// 将属性写入文件
try (FileOutputStream output = new FileOutputStream("config.properties")) {
properties.store(output, "This is a comment");
} catch (IOException e) {
e.printStackTrace();
}
4、默认值:
java
// 获取属性值,如果属性不存在,返回默认值
String value = properties.getProperty("key3", "default");
System.out.println(value); // 输出 "default"
5、遍历属性:
java
// 遍历所有属性
for (String key : properties.stringPropertyNames()) {
String value = properties.getProperty(key);
System.out.println(key + ": " + value);
}
6、应用场景:
1、配置文件管理: 主要用于读取和写入配置文件,存储应用程序的配置信息。
2、国际化: 在国际化中,可以使用 Properties 存储不同语言的文本。
3、属性映射: 用于管理键值对形式的属性,类似于字典。
Properties 类是处理配置文件和属性映射的便捷工具,在许多 Java 应用程序中广泛用于管理配置信息。
这些集合类提供了各种不同的数据结构和性能特性,以满足不同的需求。根据你的具体需求和使用情境,你可以选择适当的集合类来存储和管理数据。