net112企业建站系统,烟台网站建设公司报价,松江手机网站开发,汉源网站建设文章目录 概念Collection 接口概念示例 Iterator 迭代器基本操作#xff1a;并发修改异常增强循环遍历数组#xff1a;遍历集合#xff1a;遍历字符串#xff1a;限制 list接口ListIteratorArrayList创建 ArrayList#xff1a;添加元素#xff1a;获取元素#xff1a;修… 文章目录 概念Collection 接口概念示例 Iterator 迭代器基本操作并发修改异常增强循环遍历数组遍历集合遍历字符串限制 list接口ListIteratorArrayList创建 ArrayList添加元素获取元素修改元素删除元素获取列表大小遍历元素注意事项源码扩容 LinkedList创建 LinkedList添加元素在指定位置插入元素获取元素删除元素删除指定位置的元素遍历元素实现队列和栈注意事项源码链表 set接口概况 HashSet概况 LinkedHashSet概况 TreeSet概况 Collections 工具类概况 Map接口概况 HashMap概况源码扩容 LinkedHashMap概况 Hashtable概况 TreeMap概况 Properties概况 概念
在Java中集合是一种用于存储和处理多个对象的框架。Java集合框架提供了一组接口和类用于表示和操作不同类型的集合数据结构。以下是Java集合框架的主要概念 接口Interfaces Collection接口 定义了一组通用的方法适用于所有集合类。它是所有集合框架的根接口。Set接口 继承自Collection接口表示不包含重复元素的集合。List接口 继承自Collection接口表示有序且可重复的集合。Map接口 不继承自Collection接口表示键值对的集合。 类Classes ArrayList 基于数组实现的动态数组实现了List接口。LinkedList 基于链表实现的双向链表也实现了List接口。HashSet 使用哈希表实现的Set接口不保证元素的顺序。TreeSet 基于红黑树实现的Set接口以有序方式存储元素。HashMap 使用哈希表实现的Map接口存储键值对。TreeMap 基于红黑树实现的Map接口以键的自然顺序或自定义顺序存储键值对。 迭代器Iterator 用于遍历集合中的元素是集合框架中通用的迭代方式。 泛型Generics 集合框架使用泛型来提供类型安全性允许在编译时检测类型错误。 自动装箱和拆箱 集合框架支持自动装箱将基本数据类型转换为对应的包装类和拆箱将包装类转换为基本数据类型。 并发集合 Java还提供了一些在多线程环境下安全使用的并发集合如ConcurrentHashMap。
使用Java集合框架可以轻松地处理各种数据结构选择适当的集合类可以提高程序的效率和可读性。
Collection 接口
概念
Java 中的 Collection 接口是 Java 集合框架的根接口它定义了一组通用的方法可以用于操作和处理各种集合。Collection 接口派生出许多子接口和实现类包括 Set、List 和 Queue。
以下是 Collection 接口的主要方法 基本操作 int size(): 返回集合中的元素个数。boolean isEmpty(): 判断集合是否为空。boolean contains(Object element): 判断集合是否包含指定的元素。boolean add(E element): 向集合中添加一个元素。boolean remove(Object element): 从集合中移除指定的元素。boolean containsAll(Collection? c): 判断集合是否包含给定集合的所有元素。boolean addAll(Collection? extends E c): 将给定集合的所有元素添加到集合中。boolean removeAll(Collection? c): 移除集合中与给定集合相同的所有元素。void clear(): 清空集合中的所有元素。 集合查找和迭代 IteratorE iterator(): 返回一个用于迭代集合的迭代器。Object[] toArray(): 将集合转换为数组。T T[] toArray(T[] a): 将集合转换为指定类型的数组。 集合操作 boolean retainAll(Collection? c): 仅保留集合中与给定集合相同的元素移除其他元素。 比较和相等 boolean equals(Object o): 判断集合是否与另一个对象相等。int hashCode(): 返回集合的哈希码值。
Collection 接口的实现类包括 ArrayList、LinkedList、HashSet 等它们提供了不同的数据结构和行为以满足不同的需求。此外Collection 接口的子接口 Set、List 和 Queue 分别定义了集合的不同特性。
示例
当涉及到 Collection 接口和其实现类时代码示例的具体内容会取决于你希望使用的集合类型和操作。以下是一些基本的代码示例涵盖了一些常见的集合操作。
使用 ArrayList 实现 Collection 接口
import java.util.ArrayList;
import java.util.Collection;public class CollectionExample {public static void main(String[] args) {// 创建 ArrayList 实例CollectionString myCollection new ArrayList();// 添加元素myCollection.add(Apple);myCollection.add(Banana);myCollection.add(Orange);// 判断集合是否为空boolean isEmpty myCollection.isEmpty();System.out.println(Is Collection empty? isEmpty);// 获取集合大小int size myCollection.size();System.out.println(Collection size: size);// 判断集合是否包含特定元素boolean containsBanana myCollection.contains(Banana);System.out.println(Collection contains Banana? containsBanana);// 移除元素myCollection.remove(Orange);// 遍历集合System.out.println(Collection elements:);for (String element : myCollection) {System.out.println(element);}// 清空集合myCollection.clear();System.out.println(Is Collection empty after clearing? myCollection.isEmpty());}
}使用 HashSet 实现 Set 接口
import java.util.HashSet;
import java.util.Set;public class SetExample {public static void main(String[] args) {// 创建两个集合SetString set1 new HashSet(Arrays.asList(Apple, Banana, Orange));SetString set2 new HashSet(Arrays.asList(Banana, Orange, Grapes));// 计算两个集合的交集SetString intersection new HashSet(set1);intersection.retainAll(set2);// 打印交集System.out.println(Intersection of set1 and set2: intersection);// 将集合转换为数组String[] arrayFromSet1 set1.toArray(new String[0]);String[] arrayFromSet2 set2.toArray(new String[0]);// 打印转换后的数组System.out.println(Array from set1: Arrays.toString(arrayFromSet1));System.out.println(Array from set2: Arrays.toString(arrayFromSet2));// 创建 HashSet 实例SetString mySet new HashSet();// 添加元素mySet.add(Red);mySet.add(Green);mySet.add(Blue);// 判断集合是否包含特定元素boolean containsGreen mySet.contains(Green);System.out.println(Set contains Green? containsGreen);// 遍历集合System.out.println(Set elements:);for (String element : mySet) {System.out.println(element);}}
}这只是一个简单的示例你可以根据需要进行更复杂的集合操作和使用其他实现类。希望这些例子能帮助你入门 Java 集合框架。
Iterator 迭代器
Iterator 接口是 Java 集合框架中用于遍历集合元素的迭代器接口。它定义了一组用于在集合中迭代元素的方法。迭代器提供了一种统一的方式允许你遍历集合中的元素而不必关心集合的底层实现。
以下是 Iterator 接口的主要方法
基本操作
boolean hasNext(): 判断是否还有下一个元素。E next(): 返回迭代器的下一个元素。void remove(): 从集合中移除迭代器最后返回的元素可选操作。
使用 Iterator 的示例代码如下
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;public class IteratorExample {public static void main(String[] args) {// 创建一个 ArrayListListString myList new ArrayList();myList.add(Apple);myList.add(Banana);myList.add(Orange);// 获取迭代器IteratorString iterator myList.iterator();// 使用迭代器遍历集合System.out.println(Elements in the list:);while (iterator.hasNext()) {String element iterator.next();System.out.println(element);// 可选操作在遍历过程中移除元素if (element.equals(Banana)) {iterator.remove();}}// 打印修改后的集合System.out.println(List after removing Banana: myList);}
}在这个例子中我们使用 ArrayList 创建了一个列表然后通过 iterator() 方法获取了该列表的迭代器。接着使用 while 循环和迭代器的 hasNext() 和 next() 方法遍历集合中的元素。如果需要在遍历的同时可以使用迭代器的 remove() 方法从集合中移除元素这是可选操作。
输出应该类似于以下内容
Elements in the list:
Apple
Banana
Orange
List after removing Banana: [Apple, Orange]这个例子演示了如何使用 Iterator 遍历集合元素并且在遍历的过程中进行一些操作。
并发修改异常
在 Java 中如果在使用迭代器遍历集合的过程中同时对集合进行了结构性修改添加、删除等就可能触发并发修改异常ConcurrentModificationException。
这种异常是一种检测到多个线程并发访问集合的机制主要是为了避免由于一个线程修改集合的结构而导致另一个线程遍历集合时出现不一致的情况。
以下是一个示例演示了在使用迭代器遍历集合时触发并发修改异常的情况
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;public class ConcurrentModificationExample {public static void main(String[] args) {ListString myList new ArrayList();myList.add(Apple);myList.add(Banana);myList.add(Orange);IteratorString iterator myList.iterator();// 使用迭代器遍历集合while (iterator.hasNext()) {String element iterator.next();System.out.println(element);// 在遍历过程中尝试添加元素会触发并发修改异常if (element.equals(Banana)) {myList.remove(Banana);}}}
}在上述示例中当迭代器遍历到 “Banana” 时尝试在集合中添加 “Grapes”这会导致并发修改异常。在多线程环境中这种并发修改可能会导致不确定的行为。
为了避免并发修改异常可以采取以下措施 使用专门的并发集合 Java 提供了一些专门设计用于多线程并发访问的集合类如 ConcurrentHashMap、CopyOnWriteArrayList 等。 使用同步块 在进行迭代时可以使用同步块来确保在遍历期间不会有其他线程修改集合。 使用迭代器的安全删除方法 迭代器的 remove() 方法是安全的可以用于在迭代期间移除元素。
示例中的异常触发是因为在遍历时进行了添加操作这打破了迭代器的一致性。为了避免这种情况最好在迭代过程中只使用迭代器的 remove() 方法来进行修改。
增强循环
Java 中的增强 for 循环也称为 foreach 循环是一种简化数组和集合遍历的语法糖。它提供了一种更简洁、可读性更好的方式来遍历数组、集合和其他 Iterable 对象。
语法格式如下
for (element_type element : iterable) {// 循环体
}其中
element_type 是集合中元素的类型。element 是循环变量表示每次迭代中的当前元素。iterable 是要遍历的数组、集合或其他 Iterable 对象。
下面是一些使用增强 for 循环的示例
遍历数组
int[] numbers {1, 2, 3, 4, 5};for (int number : numbers) {System.out.println(number);
}遍历集合
import java.util.ArrayList;
import java.util.List;ListString fruits new ArrayList();
fruits.add(Apple);
fruits.add(Banana);
fruits.add(Orange);for (String fruit : fruits) {System.out.println(fruit);
}遍历字符串
String message Hello;for (char ch : message.toCharArray()) {System.out.println(ch);
}增强 for 循环适用于任何实现了 Iterable 接口的类包括数组、集合等。需要注意的是在使用增强 for 循环遍历集合时不能在循环中修改集合的结构否则会抛出 ConcurrentModificationException 异常。如果需要进行修改建议使用迭代器或普通 for 循环。
限制
当使用增强 for 循环遍历集合时Java 语言设计使得在循环内部隐藏了迭代器的具体细节。增强 for 循环是一种简洁的语法糖让我们可以更方便地遍历数组或集合。然而这种简洁性带来了一些限制。
在增强 for 循环中我们不能直接访问迭代器的一些方法比如 remove。因此如果在增强 for 循环中尝试使用迭代器的 remove 方法就会抛出异常。
相比之下普通的 for 循环和显式使用迭代器的方式更为灵活。在普通的 for 循环中我们可以显式地获取迭代器并直接调用迭代器的 remove 方法这是因为我们有更多的控制权。
下面是一个对比的例子
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;public class Example {public static void main(String[] args) {ListString fruits new ArrayList();fruits.add(Apple);fruits.add(Banana);fruits.add(Orange);// 使用增强 for 循环尝试使用迭代器的 remove 方法会抛出异常for (String fruit : fruits) {// 尝试使用迭代器的 remove 方法会抛出异常// fruits.remove(fruit); // 这行代码会抛出异常}// 使用普通的 for 循环和迭代器不会抛出异常for (IteratorString iterator fruits.iterator(); iterator.hasNext();) {String fruit iterator.next();iterator.remove(); // 可以正常使用迭代器的 remove 方法}System.out.println(List after removing elements: fruits);}
}总体来说如果你需要在遍历集合的同时进行修改最好选择普通的 for 循环和显式使用迭代器的方式。增强 for 循环则更适用于简单的遍历操作。
list接口
List 接口是 Java 集合框架中定义的一个接口它继承自 Collection 接口表示一个有序、可重复的集合。List 支持按索引访问元素允许插入、更新和删除元素。Java 中常见的实现 List 接口的类包括 ArrayList、LinkedList 和 Vector。
以下是 List 接口的主要特点和方法 有序性 List 中的元素是有序的即它们按照插入的顺序排列。 可重复性 List 允许包含重复的元素相同的元素可以出现多次。 索引访问 List 支持按索引访问元素。通过索引可以获取、设置、插入和删除元素。 动态大小 List 集合的大小可以根据需要动态变化。
以下是 List 接口的一些常用方法
boolean add(E element): 将指定的元素追加到列表的末尾。void add(int index, E element): 将指定的元素插入列表中的指定位置。boolean remove(Object o): 从列表中删除指定元素的第一个匹配项。E remove(int index): 删除列表中指定位置的元素。E get(int index): 返回列表中指定位置的元素。int indexOf(Object o): 返回列表中第一次出现的指定元素的索引。int size(): 返回列表中的元素数。
示例使用 ArrayList 实现 List 接口
import java.util.ArrayList;
import java.util.List;public class ListExample {public static void main(String[] args) {// 创建一个 ArrayListListString fruits new ArrayList();// 添加元素fruits.add(Apple);fruits.add(Banana);fruits.add(Orange);// 遍历元素for (String fruit : fruits) {System.out.println(fruit);}// 获取元素String firstFruit fruits.get(0);System.out.println(First Fruit: firstFruit);// 插入元素fruits.add(1, Grapes);// 删除元素fruits.remove(Banana);// 输出修改后的列表System.out.println(Modified List: fruits);}
}上述示例演示了如何使用 ArrayList 实现的 List 接口进行元素的添加、访问、插入和删除操作。List 接口提供了丰富的方法使得对有序集合的操作变得灵活和方便。
ListIterator
ListIterator 接口是 Iterator 接口的子接口专门为实现 List 接口的集合提供了一种强化的迭代器。与普通的迭代器相比ListIterator 提供了双向遍历的能力并支持在迭代过程中修改列表的结构。
以下是 ListIterator 接口的主要方法 双向遍历 boolean hasPrevious(): 如果列表在迭代器当前位置的前面有元素则返回 true。E previous(): 返回列表中的前一个元素并将迭代器的位置向前移动。 索引位置 int nextIndex(): 返回迭代器当前位置之后的元素的索引。int previousIndex(): 返回迭代器当前位置之前的元素的索引。 修改列表结构 void add(E e): 将指定的元素插入列表。void set(E e): 用指定的元素替换由 next 或 previous 返回的最后一个元素可选操作。void remove(): 从列表中移除由 next 或 previous 返回的最后一个元素可选操作。
使用 ListIterator 进行双向遍历和修改列表的示例
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;public class ListIteratorExample {public static void main(String[] args) {ListString fruits new ArrayList();fruits.add(Apple);fruits.add(Banana);fruits.add(Orange);// 获取 ListIteratorListIteratorString listIterator fruits.listIterator();// 向前遍历while (listIterator.hasNext()) {String fruit listIterator.next();System.out.println(fruit);}// 向后遍历并修改列表while (listIterator.hasPrevious()) {int index listIterator.previousIndex();String fruit listIterator.previous();System.out.println(Previous Fruit at index index : fruit);// 在迭代过程中修改列表if (fruit.equals(Banana)) {listIterator.remove();}}// 输出修改后的列表System.out.println(Modified List: fruits);}
}在上述示例中通过 listIterator() 方法获取了一个 ListIterator然后使用 hasNext()、next() 进行向前遍历使用 hasPrevious()、previous() 进行向后遍历并通过 remove() 方法在迭代过程中移除元素。ListIterator 提供了比普通迭代器更多的功能特别适用于需要在迭代过程中修改列表的情况。
ArrayList
ArrayList 具备了List接口的特性有序、重复、索引。ArrayList 集合底层的实现原理是数组大小可变。ArrayList 的特点查询速度快、增删慢。ArrayList 在 JDK8 前后的实现区别JDK7 ArrayList 像饿汉式直接创建了一个初始容量为 10 的数组每次扩容是原来长度的 1.5 倍。JDK8 ArrayList 像懒汉式一开始创建一个长度为 0 的数组当添加第一个元素的时候再创建一个容器为 10 的数组每次扩容是原来长度的 1.5 倍。ArrayList 是线程不安全的集合运行速度快。
创建 ArrayList
import java.util.ArrayList;
import java.util.List;// 创建一个 ArrayList
ListString arrayList new ArrayList();添加元素
arrayList.add(Apple);
arrayList.add(Banana);
arrayList.add(Orange);获取元素
String firstFruit arrayList.get(0);
System.out.println(First Fruit: firstFruit);修改元素
arrayList.set(1, Grapes);
System.out.println(Modified List: arrayList);删除元素
arrayList.remove(Orange);
System.out.println(List after removing Orange: arrayList);获取列表大小
int size arrayList.size();
System.out.println(List Size: size);遍历元素
System.out.println(List Elements:);
for (String fruit : arrayList) {System.out.println(fruit);
}注意事项
ArrayList 支持存储任意类型的元素包括 null。在默认情况下ArrayList 的初始容量为 10。当元素数量超过当前容量时ArrayList 会自动进行扩容。在删除元素时ArrayList 会自动调整大小但可能会导致内存浪费。可以使用 trimToSize() 方法来减小容量以节省空间。ArrayList 不是线程安全的如果在多个线程中同时修改需要采取额外的同步措施。
总体而言ArrayList 是一个灵活且常用的集合类适用于需要动态管理元素集合的情况。
源码扩容
ArrayList 的扩容机制涉及到动态数组的容量调整。当元素数量超过当前数组容量时会触发扩容。以下是 ArrayList 的扩容机制的主要步骤 计算新容量 新容量通常是当前容量的 1.5 倍即 oldCapacity * 1.5这是为了在扩容后减小不必要的空间浪费。如果新容量小于某个阈值MIN_CAPACITY_INCREMENT则使用该阈值作为新容量。 创建新数组 使用新的容量创建一个新的数组。 复制元素 将当前数组中的所有元素复制到新数组中。这是通过 System.arraycopy 来实现的效率相对较高。 更新引用 将 ArrayList 内部的引用指向新的数组使后续的操作都基于新数组进行。
以下是 ArrayList 源码中的部分扩容相关的代码
private void grow(int minCapacity) {// 当前数组容量int oldCapacity elementData.length;// 计算新容量1.5倍增长int newCapacity oldCapacity (oldCapacity 1);// 如果新容量小于所需容量则使用所需容量if (newCapacity - minCapacity 0)newCapacity minCapacity;// 如果新容量大于数组最大容量则使用最大容量if (newCapacity - MAX_ARRAY_SIZE 0)newCapacity hugeCapacity(minCapacity);// 创建新数组并复制元素elementData Arrays.copyOf(elementData, newCapacity);
}private static int hugeCapacity(int minCapacity) {if (minCapacity 0) // overflowthrow new OutOfMemoryError();return (minCapacity MAX_ARRAY_SIZE) ?Integer.MAX_VALUE :MAX_ARRAY_SIZE;
}上述代码是 ArrayList 中的 grow 方法和 hugeCapacity 方法的部分实现。grow 方法负责实际的扩容操作而 hugeCapacity 方法用于计算新容量时的一些边界检查。
需要注意的是ArrayList 的扩容机制是在 add 操作中触发的。当元素数量达到数组容量时会调用 grow 方法进行扩容。源码中还包含了一些其他细节如对最大容量的限制等。这是 ArrayList 实现动态数组扩容的基本原理。
LinkedList
LinkedList 是 Java 集合框架中的一个类实现了 List 接口。它使用双向链表Doubly Linked List实现每个节点包含一个元素和对前后节点的引用。以下是关于 LinkedList 的一些重要概念和用法
创建 LinkedList
import java.util.LinkedList;// 创建一个 LinkedList
LinkedListString linkedList new LinkedList();添加元素
linkedList.add(Apple);
linkedList.add(Banana);
linkedList.add(Orange);在指定位置插入元素
linkedList.add(1, Grapes);获取元素
String firstElement linkedList.getFirst();
String lastElement linkedList.getLast();删除元素
linkedList.remove(Banana);删除指定位置的元素
linkedList.remove(1);遍历元素
for (String fruit : linkedList) {System.out.println(fruit);
}实现队列和栈
// 作为队列使用
linkedList.offer(Mango);
String removedFromQueue linkedList.poll();// 作为栈使用
linkedList.push(Cherry);
String poppedFromStack linkedList.pop();注意事项
LinkedList 支持快速的插入和删除操作但在随机访问时性能较差。链表结构使得在头部和尾部进行插入和删除元素非常高效。LinkedList 既实现了 List 接口也实现了 Queue 和 Deque 接口可以用作队列或栈的实现。LinkedList 不是线程安全的如果在多个线程中同时修改需要采取额外的同步措施。
LinkedList 在某些场景下比较适用例如需要频繁插入和删除元素的情况。它提供了一些额外的操作如在头部和尾部插入和删除元素以及作为队列或栈使用的功能。
源码链表
LinkedList 的底层机制是基于双向链表实现的。每个节点包含了一个元素实际数据以及对前一个节点和后一个节点的引用。以下是 LinkedList 的底层机制的主要特点 节点结构 LinkedList 的节点是一个包含元素和两个引用的结构。每个节点有一个指向前一个节点的引用prev和一个指向后一个节点的引用next。 首尾引用 LinkedList 维护了两个特殊的节点即头节点first和尾节点last。头节点的 prev 引用为 null尾节点的 next 引用为 null。 元素添加 在 LinkedList 中元素的添加涉及到创建一个新的节点并调整节点的引用将新节点插入到链表的合适位置。 元素删除 删除元素时找到对应节点调整前一个节点和后一个节点的引用然后释放对应节点的内存。 随机访问 LinkedList 并不支持通过索引直接访问元素。如果需要按索引访问元素需要遍历链表找到对应位置的节点。
以下是 LinkedList 部分相关的源码片段展示了节点结构和添加元素的过程
private static class NodeE {E item;NodeE prev;NodeE next;Node(NodeE prev, E element, NodeE next) {this.item element;this.prev prev;this.next next;}
}public boolean add(E e) {linkLast(e);return true;
}private void linkLast(E e) {final NodeE l last;final NodeE newNode new Node(l, e, null);last newNode;if (l null)first newNode;elsel.next newNode;size;modCount;
}上述代码片段展示了 LinkedList 中的节点结构和添加元素的过程。Node 类表示链表中的节点linkLast 方法用于在链表末尾添加新元素。在添加元素时首先创建一个新的节点然后调整链表中的引用最后更新链表的大小和修改计数器。这个过程是基于链表结构的插入操作。
set接口
概况
在 Java 中Set 接口是集合框架中定义的一种集合类型它继承自 Collection 接口。Set 表示不包含重复元素的集合它不保证集合中元素的顺序。Set 接口的主要实现类有 HashSet、LinkedHashSet 和 TreeSet。
以下是 Set 接口的主要特点和方法 不允许重复元素 Set 不允许集合中存在相同的元素即集合中的元素是唯一的。 无序性 Set 不保证元素的顺序。具体实现类的迭代顺序可能会根据具体的实现方式不同而有所区别。 基本方法 Set 继承自 Collection 接口因此包含了 add、remove、contains、size 等基本方法。 实现类 常见的 Set 接口的实现类包括 HashSet: 基于哈希表实现无序。LinkedHashSet: 继承自 HashSet具有按插入顺序排序的特性。TreeSet: 基于红黑树实现元素按照自然顺序或指定比较器排序。 示例代码
import java.util.HashSet;
import java.util.Set;public class SetExample {public static void main(String[] args) {// 创建 HashSet 实例SetString hashSet new HashSet();// 添加元素hashSet.add(Apple);hashSet.add(Banana);hashSet.add(Orange);// 元素不允许重复重复元素不会被添加hashSet.add(Apple);// 输出集合元素System.out.println(HashSet: hashSet);// 检查元素是否存在boolean containsBanana hashSet.contains(Banana);System.out.println(Contains Banana: containsBanana);// 移除元素hashSet.remove(Orange);// 输出修改后的集合System.out.println(Modified HashSet: hashSet);}
}上述代码演示了如何使用 HashSet 实现 Set 接口包括添加元素、检查元素是否存在、移除元素等基本操作。
总体而言Set 接口提供了一种不包含重复元素的集合它的实现类提供了不同的性能和行为特点可以根据具体需求选择合适的实现。
HashSet
概况
HashSet 是 Java 集合框架中实现了 Set 接口的类它基于哈希表hash table实现。以下是关于 HashSet 的一些重要特点和用法 不允许重复元素 HashSet 不允许集合中存在相同的元素即集合中的元素是唯一的。如果尝试向 HashSet 中添加已存在的元素该操作将被忽略。 无序性 HashSet 不保证元素的顺序。具体迭代的顺序可能会受到哈希表实现的影响。 基于哈希表 HashSet 的底层实现是一个哈希表它使用哈希码hash code来存储和检索元素。这使得查找、插入和删除元素的操作具有较快的平均时间复杂度。 允许空元素 HashSet 允许存储空元素null。 实现了 Set 接口 HashSet 是 Set 接口的实现类因此它继承了 Set 接口中定义的方法如 add、remove、contains 等。 示例代码
import java.util.HashSet;
import java.util.Set;public class HashSetExample {public static void main(String[] args) {// 创建 HashSet 实例SetString hashSet new HashSet();// 添加元素hashSet.add(Apple);hashSet.add(Banana);hashSet.add(Orange);// 元素不允许重复重复元素不会被添加hashSet.add(Apple);// 输出集合元素System.out.println(HashSet: hashSet);// 检查元素是否存在boolean containsBanana hashSet.contains(Banana);System.out.println(Contains Banana: containsBanana);// 移除元素hashSet.remove(Orange);// 输出修改后的集合System.out.println(Modified HashSet: hashSet);}
}上述代码演示了如何使用 HashSet包括创建实例、添加元素、检查元素是否存在、移除元素等基本操作。需要注意的是由于 HashSet 的无序性输出的集合元素可能不按照添加的顺序排列。
LinkedHashSet
概况
LinkedHashSet 是 Java 集合框架中的一个实现了 Set 接口的类它是 HashSet 的子类。LinkedHashSet 继承了 HashSet并且在内部使用链表维护元素的插入顺序。以下是关于 LinkedHashSet 的一些重要特点和用法 有序性 与 HashSet 不同LinkedHashSet 保留了元素的插入顺序。遍历集合时元素的顺序与它们被添加到集合中的顺序一致。 不允许重复元素 LinkedHashSet 不允许集合中存在相同的元素即集合中的元素是唯一的。如果尝试向 LinkedHashSet 中添加已存在的元素该操作将被忽略。 基于哈希表和链表 LinkedHashSet 的底层实现既包括了哈希表又包括了链表。哈希表用于快速查找元素链表用于维护插入顺序。 允许空元素 LinkedHashSet 允许存储空元素null。 实现了 Set 接口 LinkedHashSet 是 Set 接口的实现类因此它继承了 Set 接口中定义的方法如 add、remove、contains 等。 示例代码
import java.util.LinkedHashSet;
import java.util.Set;public class LinkedHashSetExample {public static void main(String[] args) {// 创建 LinkedHashSet 实例SetString linkedHashSet new LinkedHashSet();// 添加元素linkedHashSet.add(Apple);linkedHashSet.add(Banana);linkedHashSet.add(Orange);// 元素不允许重复重复元素不会被添加linkedHashSet.add(Apple);// 输出集合元素System.out.println(LinkedHashSet: linkedHashSet);// 检查元素是否存在boolean containsBanana linkedHashSet.contains(Banana);System.out.println(Contains Banana: containsBanana);// 移除元素linkedHashSet.remove(Orange);// 输出修改后的集合System.out.println(Modified LinkedHashSet: linkedHashSet);}
}上述代码演示了如何使用 LinkedHashSet包括创建实例、添加元素、检查元素是否存在、移除元素等基本操作。由于 LinkedHashSet 的有序性输出的集合元素会按照插入顺序排列。
TreeSet
概况
TreeSet 是 Java 集合框架中的一个实现了 SortedSet 接口的类它继承了 AbstractSet 类。与 HashSet 和 LinkedHashSet 不同TreeSet 是基于红黑树Red-Black Tree实现的。以下是关于 TreeSet 的一些重要特点和用法 有序性 TreeSet 是有序的集合它根据元素的自然顺序或者通过提供的比较器进行排序。因此遍历 TreeSet 得到的元素是按照升序或降序排列的。 不允许重复元素 TreeSet 不允许集合中存在相同的元素即集合中的元素是唯一的。如果尝试向 TreeSet 中添加已存在的元素该操作将被忽略。 基于红黑树 TreeSet 的底层实现是一个红黑树这是一种自平衡的二叉搜索树。红黑树的特性确保了插入、删除和查找等操作的较快平均时间复杂度。 允许空元素 TreeSet 允许存储空元素null。 实现了 SortedSet 接口 由于 TreeSet 实现了 SortedSet 接口它提供了一些按顺序操作的方法如 first()、last()、headSet()、tailSet() 等。 示例代码
import java.util.TreeSet;
import java.util.Set;public class TreeSetExample {public static void main(String[] args) {// 创建 TreeSet 实例SetString treeSet new TreeSet();// 添加元素treeSet.add(Apple);treeSet.add(Banana);treeSet.add(Orange);// 元素不允许重复重复元素不会被添加treeSet.add(Apple);// 输出集合元素有序System.out.println(TreeSet: treeSet);// 检查元素是否存在boolean containsBanana treeSet.contains(Banana);System.out.println(Contains Banana: containsBanana);// 移除元素treeSet.remove(Orange);// 输出修改后的集合System.out.println(Modified TreeSet: treeSet);}
}上述代码演示了如何使用 TreeSet包括创建实例、添加元素、检查元素是否存在、移除元素等基本操作。由于 TreeSet 的有序性输出的集合元素会按照自然顺序或比较器指定的顺序排列。
Collections 工具类
概况
Collections 是 Java 集合框架中的一个工具类提供了一系列静态方法用于对集合进行操作和处理。这个工具类包含了各种实用的方法涵盖了对列表、集合、映射等不同类型的集合进行排序、查找、替换、同步等操作。以下是一些常用的 Collections 类的方法 排序 sort(ListT list): 对列表进行自然顺序排序。sort(ListT list, Comparator? super T c): 使用指定的比较器对列表进行排序。reverse(List? list): 反转列表中元素的顺序。 查找和替换 binarySearch(List? extends Comparable? super T list, T key): 使用二分查找算法在有序列表中查找指定元素。binarySearch(List? extends T list, T key, Comparator? super T c): 使用指定的比较器在有序列表中查找指定元素。replaceAll(ListT list, T oldVal, T newVal): 替换列表中的所有旧元素为新元素。 同步 synchronizedList(ListT list): 返回由指定列表支持的同步线程安全列表。synchronizedSet(SetT s): 返回由指定集合支持的同步线程安全集合。synchronizedMap(MapK,V m): 返回由指定映射支持的同步线程安全映射。 不可修改 unmodifiableList(List? extends T list): 返回指定列表的不可修改视图。unmodifiableSet(Set? extends T s): 返回指定集合的不可修改视图。unmodifiableMap(Map? extends K,? extends V m): 返回指定映射的不可修改视图。 其他操作 shuffle(List? list): 随机置换列表中的元素。frequency(Collection? c, Object o): 返回指定集合中指定元素的出现次数。reverseOrder(): 返回一个比较器强制逆序比较。
示例代码
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;public class CollectionsExample {public static void main(String[] args) {// 创建一个列表ListString myList new ArrayList();myList.add(Apple);myList.add(Banana);myList.add(Orange);// 排序Collections.sort(myList);System.out.println(Sorted List: myList);// 反转Collections.reverse(myList);System.out.println(Reversed List: myList);// 随机置换Collections.shuffle(myList);System.out.println(Shuffled List: myList);// 查找元素int index Collections.binarySearch(myList, Banana);System.out.println(Index of Banana: index);// 创建不可修改的视图ListString unmodifiableList Collections.unmodifiableList(myList);// 尝试修改不可修改视图将抛出 UnsupportedOperationException// unmodifiableList.add(Grapes);}
}上述代码演示了使用 Collections 类的一些方法包括排序、反转、随机置换、查找等。需要注意的是通过 unmodifiableList 方法创建的不可修改视图尝试在这个视图上进行修改会抛出 UnsupportedOperationException 异常。
Map接口
概况
Map 接口是 Java 集合框架中表示键值对的一种集合类型。它表示一组键值对的映射关系其中每个键key对应一个值value。Map 接口的主要实现类有 HashMap、LinkedHashMap、TreeMap 等。以下是关于 Map 接口的一些重要特点和用法 键值对映射 Map 存储的是键值对每个键对应一个值。键和值都可以是任意类型的对象但键必须是唯一的。 不允许重复键 在一个 Map 中不允许存在重复的键。如果尝试使用已存在的键添加新值新值将覆盖旧值。 有序性 Map 接口不保证键值对的顺序具体实现类有不同的有序性特点。 HashMap: 无序键值对的顺序不受控制。LinkedHashMap: 有序键值对按照插入顺序或访问顺序排序。TreeMap: 有序键值对按照键的自然顺序或比较器排序。 允许空键和空值 Map 接口允许键和值都为 null。 基本方法 Map 提供了一系列基本方法如 put添加键值对、get获取值、remove移除键值对、containsKey检查键是否存在、containsValue检查值是否存在等。 实现类 常见的 Map 接口的实现类包括 HashMap: 基于哈希表实现无序。LinkedHashMap: 继承自 HashMap有序。TreeMap: 基于红黑树实现有序。 示例代码
import java.util.HashMap;
import java.util.Map;public class MapExample {public static void main(String[] args) {// 创建 HashMap 实例MapString, Integer hashMap new HashMap();// 添加键值对hashMap.put(Apple, 10);hashMap.put(Banana, 5);hashMap.put(Orange, 8);// 获取值int appleCount hashMap.get(Apple);System.out.println(Number of Apples: appleCount);// 检查键是否存在boolean containsKey hashMap.containsKey(Grapes);System.out.println(Contains Grapes: containsKey);// 移除键值对hashMap.remove(Banana);// 输出修改后的 MapSystem.out.println(Modified Map: hashMap);}
}上述代码演示了如何使用 HashMap 实现 Map 接口包括添加键值对、获取值、检查键是否存在、移除键值对等基本操作。
HashMap
概况
HashMap 是 Java 集合框架中的一个实现了 Map 接口的类它基于哈希表实现键值对的存储。以下是关于 HashMap 的一些重要特点和用法 键值对映射 HashMap 存储的是键值对每个键对应一个值。键和值都可以是任意类型的对象但键必须是唯一的。 无序性 HashMap 不保证键值对的顺序即插入顺序不会影响遍历顺序。具体遍历的顺序可能随时间而变化。 允许空键和空值 HashMap 允许键和值都为 null。 基于哈希表 HashMap 的底层实现是一个哈希表它使用键的哈希码来存储和检索值。这使得查找、插入和删除键值对的操作具有较快的平均时间复杂度。 动态扩容 HashMap 具有动态扩容的特性当元素数量达到一定阈值时自动进行扩容以保持较低的负载因子提高性能。 负载因子 负载因子是 HashMap 中用于判断是否需要扩容的一个重要参数默认为 0.75。当元素数量达到负载因子与容量的乘积时触发扩容。 常见方法 HashMap 提供了一系列常见的方法如 put添加键值对、get获取值、remove移除键值对、containsKey检查键是否存在、containsValue检查值是否存在等。 示例代码
import java.util.HashMap;
import java.util.Map;public class HashMapExample {public static void main(String[] args) {// 创建 HashMap 实例MapString, Integer hashMap new HashMap();// 添加键值对hashMap.put(Apple, 10);hashMap.put(Banana, 5);hashMap.put(Orange, 8);// 获取值int appleCount hashMap.get(Apple);System.out.println(Number of Apples: appleCount);// 检查键是否存在boolean containsKey hashMap.containsKey(Grapes);System.out.println(Contains Grapes: containsKey);// 移除键值对hashMap.remove(Banana);// 输出修改后的 HashMapSystem.out.println(Modified HashMap: hashMap);}
}上述代码演示了如何使用 HashMap包括添加键值对、获取值、检查键是否存在、移除键值对等基本操作。需要注意的是由于 HashMap 的无序性输出的键值对顺序可能与插入的顺序不一致。
源码扩容
HashMap是一种常见的数据结构它通过哈希函数将键映射到存储桶中的位置。在Java中HashMap的底层实现是基于数组和链表或红黑树的组合。以下是HashMap的底层扩容机制和数据结构
底层数据结构 数组 HashMap内部维护一个数组这个数组的每个元素都是一个存储桶。存储桶是HashMap中实际存储数据的地方。 链表或红黑树 每个数组元素存储桶可能是一个链表或一棵红黑树。这是为了解决哈希冲突的问题。当不同的键经过哈希函数映射到同一个存储桶时它们会被存储在这个存储桶对应的链表或红黑树中。
扩容机制 负载因子 HashMap维护一个负载因子默认为0.75。负载因子是指HashMap中存储的元素数量与存储桶数量的比率。当负载因子超过设定的阈值时HashMap触发扩容操作。 扩容操作 当HashMap中的元素数量达到负载因子乘以当前容量时HashMap会进行扩容。扩容涉及到创建一个新的数组通常是当前容量的两倍然后将所有元素重新分配到新的存储桶中。 重新哈希 在扩容时所有的元素需要重新计算哈希并放入新的存储桶中。这个过程叫做重新哈希。 链表转红黑树 如果链表的长度超过一定阈值8链表会被转换成红黑树以提高查找效率。
总的来说HashMap通过数组和链表或红黑树的组合来实现键值对的存储并通过负载因子和扩容机制来动态调整容量保持高效的性能。
LinkedHashMap
概况
LinkedHashMap 是 Java 集合框架中的一种具体实现类它继承自 HashMap 类除了具有 HashMap 的特性外还保留了插入顺序或访问顺序最近最少使用的特性。具体来说LinkedHashMap 维护了一个双向链表用于保持键值对的插入顺序或访问顺序。
以下是 LinkedHashMap 的一些主要特点 插入顺序 默认情况下LinkedHashMap 会按照键值对的插入顺序维护它们的顺序。新插入的键值对会被放到链表的尾部。 访问顺序 通过构造函数参数设置LinkedHashMap 可以按照键值对的访问顺序维护它们的顺序。每次访问一个键值对包括 get、put、containsKey 等操作都会将该键值对移到链表的尾部。 性能 LinkedHashMap 的性能和 HashMap 相近。由于维护了额外的链表相对于 HashMapLinkedHashMap 在插入和删除操作上可能稍微慢一些但在迭代遍历时更具有优势。 构造函数 LinkedHashMap 提供了多个构造函数允许选择是否按照插入顺序或访问顺序以及设置初始容量和负载因子等参数。
以下是一个简单的 LinkedHashMap 示例
import java.util.LinkedHashMap;
import java.util.Map;public class LinkedHashMapExample {public static void main(String[] args) {// 创建一个按插入顺序的LinkedHashMapMapString, Integer linkedHashMap new LinkedHashMap();// 添加键值对linkedHashMap.put(One, 1);linkedHashMap.put(Two, 2);linkedHashMap.put(Three, 3);// 输出顺序是插入顺序System.out.println(Insertion Order: linkedHashMap);// 访问某个键该键值对移到链表尾部linkedHashMap.get(Two);// 输出顺序是访问顺序Two 移到了最后System.out.println(Access Order: linkedHashMap);}
}在上述示例中LinkedHashMap 在默认情况下按照插入顺序维护键值对的顺序。在访问了键值对 “Two” 后该键值对被移到了链表的尾部所以在输出时按照访问顺序输出。
Hashtable
概况
Hashtable 是 Java 集合框架中的一个古老的类它实现了 Map 接口提供了键值对的存储和检索功能。Hashtable 是线程安全的这意味着多个线程可以同时访问 Hashtable 的方法而不会导致数据不一致。然而由于其线程安全性性能相对较低通常不推荐在新代码中使用而更常见的替代方案是 HashMap。
以下是 Hashtable 的一些主要特点和使用方法 线程安全 Hashtable 是同步的多个线程可以安全地同时访问 Hashtable 的方法。这是通过在每个公共方法上添加 synchronized 关键字实现的。 键和值 Hashtable 存储键值对其中键和值都是对象。键不能为 null值也不能为 null。 初始化容量和负载因子 Hashtable 可以通过构造函数指定初始容量和负载因子。初始容量是哈希表在创建时的容量负载因子是在哈希表重新调整大小之前它可以保存的键值对数与数组容量的比率。 哈希冲突解决 Hashtable 使用链表解决哈希冲突。当多个键映射到相同的哈希码时它们会存储在同一个桶中的链表中。 方法 Hashtable 提供了许多方法包括 put、get、remove 等用于操作键值对的方法。
以下是一个简单的 Hashtable 示例
import java.util.Hashtable;
import java.util.Map;public class HashtableExample {public static void main(String[] args) {// 创建一个HashtableHashtableString, Integer hashtable new Hashtable();// 添加键值对hashtable.put(One, 1);hashtable.put(Two, 2);hashtable.put(Three, 3);// 获取值int value hashtable.get(Two);System.out.println(Value for key Two: value);// 移除键值对hashtable.remove(Three);// 遍历键值对for (Map.EntryString, Integer entry : hashtable.entrySet()) {System.out.println(Key: entry.getKey() , Value: entry.getValue());}}
}在上述示例中Hashtable 被创建并用于存储键值对。通过 put 方法添加键值对通过 get 方法获取值通过 remove 方法移除键值对。最后通过 entrySet 方法遍历键值对。需要注意的是由于 Hashtable 是线程安全的它的性能相对较低因此在单线程环境下通常更推荐使用 HashMap。
TreeMap
概况
TreeMap 是 Java 集合框架中的一种实现 SortedMap 接口的有序映射。它基于红黑树Red-Black Tree实现具有以下主要特点 有序性 TreeMap 中的键值对是按照键的自然顺序或者通过构造函数提供的 Comparator 进行排序的。这使得 TreeMap 中的键值对是有序的。 红黑树 内部使用红黑树来实现映射这确保了对于常规操作插入、删除、查找的较高性能。 键和值 TreeMap 存储键值对键和值都可以是任意对象。键不能为 null但值可以为 null。 时间复杂度 对于红黑树的常规操作插入、删除、查找时间复杂度是 O(log n)其中 n 是键值对的数量。 子映射 TreeMap 提供了一系列方法如 subMap、headMap、tailMap用于获取子映射以支持范围查找。
以下是一个简单的 TreeMap 示例
import java.util.*;public class TreeMapExample {public static void main(String[] args) {// 创建一个TreeMapTreeMapString, Integer treeMap new TreeMap();// 添加键值对treeMap.put(Three, 3);treeMap.put(One, 1);treeMap.put(Four, 4);treeMap.put(Two, 2);// 遍历键值对按照键的自然顺序输出for (Map.EntryString, Integer entry : treeMap.entrySet()) {System.out.println(Key: entry.getKey() , Value: entry.getValue());}// 获取第一个和最后一个键值对System.out.println(First Entry: treeMap.firstEntry());System.out.println(Last Entry: treeMap.lastEntry());// 获取子映射包含 One 到 ThreeSortedMapString, Integer subMap treeMap.subMap(One, Three);System.out.println(SubMap: subMap);}
}在上述示例中TreeMap 被创建并用于存储键值对。通过 put 方法添加键值对通过 entrySet 方法遍历键值对。TreeMap 的输出顺序是按照键的自然顺序字符串的字典顺序输出。firstEntry 和 lastEntry 方法分别获取第一个和最后一个键值对。subMap 方法获取包含范围在 “One” 到 “Three” 之间的子映射。
Properties
概况
Properties 类是 Java 集合框架中的一种特殊实现用于处理属性文件。它继承自 Hashtable 类其中键和值都是字符串类型。通常Properties 被用来处理配置文件存储和读取应用程序的配置信息。
以下是 Properties 类的主要特点和用法 键值对存储 Properties 使用键值对的方式存储配置信息。键和值都必须是字符串。 加载和保存 Properties 可以从输入流中加载属性文件并将属性文件保存到输出流中。常见的方法有 load 和 store。 默认值 Properties 可以指定默认属性当在属性文件中找不到某个键对应的值时会返回默认值。 获取属性 通过键获取属性值的方法为 getProperty也可以使用 getProperty(String key, String defaultValue) 指定默认值。
以下是一个简单的示例展示了如何使用 Properties 类读取和写入属性文件
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Properties;public class PropertiesExample {public static void main(String[] args) {// 读取属性文件Properties properties new Properties();try (FileInputStream input new FileInputStream(config.properties)) {properties.load(input);} catch (IOException e) {e.printStackTrace();}// 获取属性值String username properties.getProperty(username);String password properties.getProperty(password, defaultPassword);System.out.println(Username: username);System.out.println(Password: password);// 写入属性文件try (FileOutputStream output new FileOutputStream(config.properties)) {properties.setProperty(newProperty, newValue);properties.store(output, Updated properties);} catch (IOException e) {e.printStackTrace();}}
}在上述示例中Properties 类首先被用于读取属性文件 config.properties 中的配置信息。然后通过 getProperty 方法获取属性值并输出到控制台。接着修改了属性值并存储到文件中以更新配置信息。