Java 集合框架

Collection 接口

集合和数组的区别

数组 :

  • 是引用数据类型的一种
  • 可以存储多个元素
  • 数组的长度是固定的 int[] arr1 = new int[10]; int[] arr2 = {1,2,3};
  • 数组即可以存储基本数据类型的数据,又可以存储引用数据类型的数据 int[] double[] String[] Student[]

集合 :

  • 是引用数据类型的一种
  • 可以存储多个元素
  • 集合的长度是可以变化的(添加元素,删除集合中的元素)
  • 集合只能存储引用数据类型的数据

Collection常用功能

添加元素:

  • boolean add(E element): 将指定的元素添加到集合中,如果成功添加,则返回true。
  • boolean addAll(Collection<? extends E> collection): 将指定集合中的所有元素添加到当前集合中,如果成功添加,则返回true。

删除元素:

  • boolean remove(Object object): 从集合中删除指定的元素,如果存在该元素,则返回true。
  • boolean removeAll(Collection<?> collection): 从集合中删除与指定集合中相同的所有元素,如果成功删除,则返回true。
  • boolean retainAll(Collection<?> collection): 从集合中仅保留与指定集合中相同的元素,如果成功保留,则返回true。
  • void clear(): 清空集合中的所有元素。

查询元素:

  • boolean contains(Object object): 判断集合中是否包含指定的元素,如果包含,则返回true。
  • boolean containsAll(Collection<?> collection): 判断集合中是否包含指定集合中的所有元素,如果包含,则返回true。
  • boolean isEmpty(): 判断集合是否为空,如果为空,则返回true。
  • int size(): 返回集合中元素的个数。

遍历元素:

  • Iterator iterator(): 返回一个用于遍历集合中元素的迭代器,通过迭代器可以依次获取集合中的元素。
  • void forEach(Consumer<? super E> action): 对集合中的每个元素执行指定的操作,可以使用Lambda表达式或方法引用。

转换为数组:

  • Object[] toArray(): 将集合转换为一个Object类型的数组,数组中的元素顺序与集合中的顺序一致。
  • T[] toArray(T[] array): 将集合转换为指定类型的数组,数组中的元素顺序与集合中的顺序一致。

这些方法只是Collection接口中的一部分,具体使用哪些方法取决于实现类的具体需求。在使用集合时,可以根据具体需求选择合适的方法来操作集合中的元素。

List 接口

List接口是Collection接口的子接口之一。它表示有序的、可重复的集合,可以按照元素的插入顺序进行访问。

通过List接口,我们可以方便地操作和管理有序的、可重复的数据集合。它提供了丰富的功能和灵活性,可以根据实际需求选择不同的实现类来使用。

List 接口的特点

  • 有序性:List中的元素是按照插入的顺序进行存储的,每个元素都有一个对应的索引值,可以通过索引值来访问和操作元素。
  • 可重复性:List中可以存储重复的元素,同一个元素可以出现多次。

List 接口常用的方法

  • 添加元素:可以使用 add() 方法将元素添加到List中,可以在指定位置插入元素。
  • 获取元素:可以使用 get() 方法根据索引获取指定位置的元素。
  • 删除元素:可以使用 remove() 方法根据索引或者元素值删除指定位置或者指定元素。
  • 修改元素:可以使用 set() 方法根据索引修改指定位置的元素。
  • 查询元素:可以使用 indexOf() 方法 和 lastIndexOf() 方法查找元素在List中的索引位置。
  • 遍历元素:可以使用for循环或者迭代器来遍历List中的元素。

List接口有多个实现类,常用的有ArrayList和LinkedList

ArrayList 集合

ArrayList是Java中常用的实现了List接口的动态数组。

它是基于数组实现的,适用于频繁访问和修改元素的场景。

它可以根据需要自动扩展和收缩容量,支持随机访问元素,并且允许包含重复元素。

ArrayList 集合的特点

  • 动态大小:ArrayList的大小可以根据需要进行动态扩展和收缩。当需要添加更多元素时,ArrayList会自动增加容量,当元素数量减少时,ArrayList会自动减小容量。
  • 随机访问:ArrayList中的元素可以通过索引进行随机访问。可以使用get()方法通过索引获得元素的值,也可以使用set()方法通过索引修改元素的值。
  • 允许重复元素:ArrayList允许存储重复的元素。这意味着可以在ArrayList中添加相同的元素。
  • 可以插入任意位置:ArrayList可以在任意位置插入元素。使用add()方法可以在指定索引位置插入元素,原来该位置的元素及后续元素会向后移动。
  • 不同步:ArrayList不是线程安全的,不适合在多线程环境下使用。如果需要在多线程环境下使用,可以考虑使用线程安全的Vector或者使用Collections类中的synchronizedList()方法对ArrayList进行同步。

ArrayList 集合常用的方法

  • add(element):向ArrayList末尾添加元素。
  • add(index, element):在指定索引位置插入元素。
  • remove(index):移除指定索引位置的元素。
  • get(index):获取指定索引位置的元素。
  • set(index, element):修改指定索引位置的元素。
  • size():获取ArrayList的大小。
  • isEmpty():判断ArrayList是否为空。
  • contains(element):判断ArrayList是否包含指定元素。
  • indexOf(element):返回指定元素第一次出现的索引。
  • lastIndexOf(element):返回指定元素最后一次出现的索引。
  • clear():清空ArrayList中的所有元素。

LinkedList 集合

LinkedList是基于链表实现的,适用于频繁插入和删除元素的场景。

LinkedList是Java中的一种双向链表,也是Java集合框架中的一部分,位于java.util包中。

LinkedList以节点的形式存储元素,每个节点都包含一个指向前一个节点和后一个节点的引用。

与ArrayList相比,LinkedList在插入和删除元素时具有更高的效率,但在随机访问元素时效率较低。

LinkedList 集合的特点

  • 双向链表:LinkedList中的元素以双向链表的形式连接,每个节点都包含一个指向前一个节点和后一个节点的引用。
  • 高效的插入和删除:由于LinkedList采用了链表结构,插入和删除元素时只需改变节点的引用,效率较高。
  • 低效的随机访问:由于LinkedList没有基于索引的随机访问能力,必须从头节点开始遍历链表才能找到指定位置的元素,因此随机访问元素的效率较低。
  • 支持泛型:LinkedList可以指定存储的元素类型,在编译时进行类型检查,避免类型转换错误。

LinkedList 集合常用的方法

  • add(E element):在列表末尾添加一个元素。
  • addFirst(E element):在列表头部添加一个元素。
  • addLast(E element):在列表末尾添加一个元素。
  • remove(int index):删除指定索引位置的元素。
  • get(int index):获取指定索引位置的元素。
  • set(int index, E element):替换指定索引位置的元素。
  • size():返回LinkedList中的元素个数。

除了上述方法外,LinkedList还有许多其他常用的方法,如contains()、indexOf()、clear()等,可以根据实际需求选择使用。

总之,LinkedList适用于需要频繁进行插入和删除操作的场景,但对于随机访问元素的需求较多的情况下,推荐使用ArrayList。正确选择合适的集合类可以提高程序的效率和性能。

Vector 集合

Vector是Java中的一个线程安全的动态数组,它实现了List接口,可以存储任意类型的对象。与ArrayList类似,Vector的内部实现也是一个可变长度的数组,当数组中的元素数量超过了当前容量时,会自动扩容。

Vector 集合的特点

  • 线程安全:Vector是线程安全的,可以在多线程环境下使用,但这也导致了一些性能上的损失。如果在单线程环境下使用,建议使用ArrayList,因为ArrayList的性能更好。
  • 动态扩容:当向Vector中添加元素时,如果当前容量不足,Vector会自动增加容量。默认情况下,容量会以原来的大小扩展一倍,可以通过指定初始容量和增长因子来自定义扩容策略。
  • 允许存储重复元素:与ArrayList一样,Vector允许存储重复的元素。
  • 支持随机访问:Vector实现了RandomAccess接口,可以通过索引来直接访问元素。这使得在Vector中进行随机访问操作非常高效。

Vector 集合常用的方法

add、remove、get、set等,这些方法与ArrayList基本相同。

此外,Vector还提供了一些特有的方法,例如addElement、elementAt、insertElementAt等,用于在指定位置插入和访问元素。

  • addElement(element):向 Vector 的末尾添加一个元素,与 add(element) 方法功能相同。
  • elementAt(index):返回指定索引位置的元素,与 get(index) 方法功能相同。
  • insertElementAt(element, index):在指定索引位置插入一个元素。

需要注意的是,由于Vector是线程安全的,所以在多线程环境下使用时,需要进行同步操作,否则可能会导致数据不一致的问题。如果在单线程环境下使用,建议使用ArrayList以提升性能。

Set 接口

Set接口是Java中的一个集合接口,它继承自Collection接口,用于存储不重复的元素。Set接口的实现类通常使用哈希表或树来存储元素,以保证元素的唯一性。

Set 接口的特点

  • 不允许重复元素:Set中不允许存储重复的元素。当尝试向Set中添加重复元素时,添加操作会被忽略。这是通过对元素的哈希值或比较方法进行判断来实现的。
  • 无序性:Set中的元素没有固定的顺序,即不能通过索引来访问元素。不同实现类对元素的存储顺序可能有所不同。
  • 高效性:Set接口的实现类通常会使用哈希表或树的数据结构来存储元素,以保证高效的查找和插入操作。因此,Set适用于需要快速判断元素是否存在的场景。

Set 接口常用的方法

  • boolean add(E element):向Set中添加指定元素,如果成功添加则返回true,如果元素已经存在则返回false。
  • boolean remove(Object element):从Set中移除指定元素,如果成功移除则返回true,如果元素不存在则返回false。
  • boolean contains(Object element):判断Set中是否包含指定元素,如果包含则返回true,如果元素不存在则返回false。
  • int size():返回Set中元素的个数。
  • boolean isEmpty():判断Set是否为空,如果为空则返回true。
  • void clear():清空Set中的所有元素。

Set接口的常用实现类有HashSet、TreeSet和LinkedHashSet。

  • HashSet:基于哈希表实现,具有较快的插入和查找操作。HashSet不保证元素的顺序。
  • TreeSet:基于红黑树实现,对元素进行排序存储。TreeSet中的元素按照自然顺序或自定义比较器进行排序。
  • LinkedHashSet:具有HashSet的快速插入和查找操作的特性,同时保持元素的插入顺序。

需要注意的是,Set接口不允许存储null元素,但可以存储一个null引用。此外,为了保证元素的唯一性,添加到Set中的元素需要正确实现equals()和hashCode()方法。

HashSet 集合

HashSet是Java中Set接口的一个实现类。它是基于哈希表实现的,可以存储不重复的元素,并且不保证元素的顺序。

HashSet的特点

  • 元素唯一性:HashSet中不能存储重复的元素,如果试图添加一个已经存在的元素,将会被忽略。
  • 无序性:HashSet中的元素没有顺序,不能通过索引访问元素。
  • 允许存储null值:HashSet可以存储null值,但只能存储一个null元素。

HashSet 集合的常用方法

  • add(E e):向HashSet中添加一个元素。
  • remove(Object o):从HashSet中移除指定元素。
  • contains(Object o):判断HashSet是否包含指定元素。
  • size():返回HashSet中元素的个数。
  • isEmpty():判断HashSet是否为空。
  • clear():清空HashSet中的所有元素。

HashSet 集合的存储原理

当我们向HashSet中添加元素时,HashSet会调用元素的hashCode()方法来获取其哈希码。哈希码是一个整数值,用于表示元素在哈希表中的存储位置。hashCode()方法是Object类的一个方法,子类可以根据自己的特定需求重写该方法。

HashSet使用哈希函数将哈希码转换为存储位置。哈希函数是一个确定性函数,它将哈希码映射到哈希表中的一个位置。理想情况下,哈希函数应该将元素均匀地分布在哈希表中的不同位置,以减少冲突的概率。

当计算出的位置已经存在元素时,HashSet会调用元素的equals()方法来比较这两个元素是否相等。equals()方法是Object类的一个方法,子类可以根据自己的特定需求重写该方法。如果两个元素相等,HashSet不会将新元素添加到集合中,以保证HashSet中的元素唯一性。如果两个元素不相等,则将新元素添加到哈希表中。

在使用HashSet时,为了保证元素的正确存储和查找,应该正确重写元素的hashCode()和equals()方法。重写规则通常是:如果两个元素相等(equals()方法返回true),则它们的哈希码也必须相等;如果两个元素不相等(equals()方法返回false),则它们的哈希码可以相等,也可以不相等,但是为了提高哈希表的效率,最好让哈希码尽量不相等。

需要注意的是,HashSet不是线程安全的。如果在多线程环境下使用HashSet,需要进行额外的同步操作,或者使用线程安全的集合类,比如ConcurrentHashSet。

另外,HashSet的初始容量和负载因子也可以进行调整,以适应不同的需求。初始容量是HashSet在创建时的初始大小,默认为16。负载因子是一个浮点数,用于控制HashSet在何时进行扩容,默认为0.75。当HashSet中的元素个数达到容量与负载因子的乘积时,HashSet会自动进行扩容,以保持较低的冲突概率。

TreeSet 集合

TreeSet是Java集合框架中的一种有序集合,它基于红黑树(Red-Black Tree)实现。与HashSet不同,TreeSet中的元素是有序的,并且不允许存储重复元素。

TreeSet通过比较元素的大小来进行排序。在添加元素时,TreeSet会根据元素的大小将其插入到合适的位置,以保持集合的有序性。在默认情况下,TreeSet使用元素的自然顺序进行排序。如果需要使用自定义的排序方式,可以在创建TreeSet时提供一个实现了Comparator接口的比较器。

由于TreeSet基于红黑树实现,它的插入、删除和查找操作的时间复杂度都是O(logN),其中N是集合中的元素数量。这使得TreeSet在需要快速查找和有序遍历元素的场景中非常有用。

需要注意的是,TreeSet不是线程安全的,如果在多线程环境中使用,需要进行额外的同步操作或使用线程安全的集合类。另外,由于TreeSet是基于比较元素的大小进行排序的,因此存储在TreeSet中的元素需要实现Comparable接口,或者在创建TreeSet时提供一个比较器。

TreeSet 集合的特点

  • 有序性:TreeSet 中的元素按照升序排列。默认情况下,TreeSet 使用元素的自然顺序进行排序,也可以通过传入自定义的 Comparator 对象来指定排序规则。
  • 唯一性:TreeSet 集合中不允许有重复的元素。这是因为 TreeSet 内部使用红黑树来存储元素,红黑树要求元素必须是可比较的,因此 TreeSet 会根据元素的比较结果来判断是否重复。
  • 高效的增删改查操作:由于 TreeSet 内部使用红黑树来存储元素,它的增删改查操作的时间复杂度为 O(logN)。

TreeSet 集合的常用方法

  • add(element):将指定的元素添加到 TreeSet 集合中。如果元素已经存在于集合中,则不会添加。
  • remove(element):从 TreeSet 集合中删除指定的元素。如果元素存在于集合中,则会被删除;否则不会有任何影响。
  • contains(element):判断 TreeSet 集合中是否包含指定的元素。如果包含,则返回 true;否则返回 false。
  • first():返回 TreeSet 集合中的第一个元素。
  • last():返回 TreeSet 集合中的最后一个元素。
  • size():返回 TreeSet 集合中的元素个数。
  • isEmpty():判断 TreeSet 集合是否为空。如果集合中没有任何元素,则返回 true;否则返回 false。
  • iterator():返回一个迭代器,可以用于遍历 TreeSet 集合中的元素。
  • clear():清空 TreeSet 集合,删除所有的元素。

需要注意的是,TreeSet 不允许插入 null 元素,因为 null 无法与其他元素进行比较。在使用 TreeSet 时,要确保元素实现了 Comparable 接口或者传入了合适的 Comparator 对象。

浅谈 LinkedHashSet 集合

LinkedHashSet是Java中的一种集合类,它是HashSet的子类。与HashSet不同的是,LinkedHashSet能够保持元素的插入顺序。

LinkedHashSet的内部实现是基于哈希表和双向链表。它使用哈希表来存储元素,并使用双向链表来维护插入顺序。因此,当遍历LinkedHashSet时,元素的顺序将与插入顺序保持一致。

与HashSet相同,LinkedHashSet也具有元素的唯一性。它使用元素的hashCode()方法来计算哈希值,然后将元素放入相应的哈希桶中。在判断元素的唯一性时,还需要使用元素的equals()方法进行比较。

由于LinkedHashSet维护了元素的插入顺序,因此在使用LinkedHashSet时,可以按照插入的顺序访问元素。这在某些场景下非常有用,例如需要按照元素的添加顺序进行迭代或展示数据。

需要注意的是,LinkedHashSet相对于HashSet来说,需要额外的内存空间来维护链表结构。因此,在空间上可能会比HashSet占用更多的内存。

总结起来,LinkedHashSet是一种可以保持元素插入顺序的集合类,它继承自HashSet并使用哈希表和双向链表实现。

Map 接口

Map接口是Java中用于存储键值对(Key-Value)数据的接口。它定义了一系列方法来操作和访问这些键值对。Map中的键是唯一的,每个键关联一个值。

Map接口的特点

  • 键值对:Map接口是以键值对(Key-Value)的形式存储数据的,每个键关联一个值。通过键可以快速地访问对应的值。
  • 唯一键:Map中的键是唯一的,不允许重复。如果插入重复的键,后面的值会覆盖前面的值。
  • 无序性:Map接口不保证元素的顺序,具体的顺序可能是随机的。如果需要有序的Map,可以使用TreeMap或LinkedHashMap。
  • 可变性:Map接口允许插入、删除和修改键值对。可以根据需要动态地更新和操作Map中的数据。
  • 遍历方式:Map接口提供了多种遍历方式,如通过键遍历、通过值遍历和通过键值对遍历。可以根据具体需求选择合适的遍历方式。
  • 容量:Map接口没有固定的容量限制,可以根据需要动态地存储大量的键值对。在插入大量数据时,需要注意内存的使用。
  • 适用性:Map接口适用于存储和管理各种类型的数据,如用户信息、配置信息、缓存数据等。通过键值对的方式,可以方便地根据键来获取对应的值,实现快速的数据查找和操作。

总结来说,Map接口提供了一种方便的方式来存储和管理键值对数据。它的特点包括键值对、唯一键、无序性、可变性、多种遍历方式、动态容量和适用性广泛。

Map 接口常用的方法

  • put(key, value):将指定的键值对添加到Map中,如果键已经存在,则会用新的值替换旧的值。
  • get(key):获取指定键对应的值,如果键不存在,则返回null。
  • remove(key):从Map中删除指定键及其对应的值。
  • containsKey(key):判断Map中是否包含指定的键。
  • containsValue(value):判断Map中是否包含指定的值。
  • keySet():返回Map中所有键的Set集合。
  • values():返回Map中所有值的Collection集合。
  • entrySet():返回Map中所有键值对的Set集合。

Map接口有多个实现类,其中常见的包括HashMap、TreeMap和LinkedHashMap。

  • HashMap 是最常用的实现类,基于哈希表实现,可以快速地插入、查找和删除键值对,但不保证元素的顺序。
  • TreeMap 基于红黑树实现,会对键进行排序,并提供了按照键的自然顺序或自定义顺序进行遍历的功能。
  • LinkedHashMap 是基于哈希表和双向链表实现的,保持了元素的插入顺序,可以按照插入顺序进行遍历。

HashMap 集合

HashMap是Java中最常用的Map接口的实现类之一,它基于哈希表实现,提供了高效的插入、查找和删除操作。HashMap允许键和值都为null,并且不保证元素的顺序。

HashMap的内部实现是一个数组,每个元素是一个链表的头节点,链表的节点包含了键值对。当插入一个键值对时,首先根据键的哈希值计算出在数组中的位置,如果该位置已经存在链表,则遍历链表找到合适的位置插入节点;如果该位置为空,则直接插入节点。当查找或删除一个键值对时,根据键的哈希值找到对应的位置,然后遍历链表找到目标节点。

HashMap的时间复杂度为O(1),即常数时间,但是在极端情况下,链表可能会变得很长,导致查找和删除操作的时间复杂度变为O(n),其中n是元素的数量。为了避免链表过长的问题,当链表的长度超过一定阈值(默认为8)时,链表会转换为红黑树,以提高查找和删除操作的效率。

除了基本的插入、查找和删除操作,HashMap还提供了一些其他常用的方法,例如size()方法用于获取元素的数量,containsKey(Object key)方法用于判断是否包含指定的键,containsValue(Object value)方法用于判断是否包含指定的值,keySet()方法用于获取所有键的集合,values()方法用于获取所有值的集合,entrySet()方法用于获取所有键值对的集合等。

HashMap 集合的特点

  • 键值对:HashMap存储的数据是键值对,每个键值对由一个键和一个值组成。
  • 哈希表:HashMap的内部实现是一个数组,每个元素是一个链表的头节点,链表的节点包含了键值对。
  • 高效性:基于哈希表的实现使得HashMap具有高效的插入、查找和删除操作,平均时间复杂度为O(1)。
  • 允许 null 键值:HashMap允许键和值都为null,但是只能有一个null键。
  • 不保证顺序:HashMap不保证元素的顺序,即插入元素的顺序不一定和遍历元素的顺序一致。

HashMap 集合的常用方法

  • 创建HashMap对象:可以使用无参构造函数创建一个空的HashMap对象,也可以使用带有初始容量和加载因子的构造函数创建HashMap对象。
  • 添加元素:使用put(key, value)方法向HashMap中添加键值对。
  • 获取元素:使用get(key)方法根据键获取对应的值。
  • 删除元素:使用remove(key)方法根据键删除对应的键值对。
  • 判断是否包含键或值:使用containsKey(key)方法判断是否包含指定的键,使用containsValue(value)方法判断是否包含指定的值。
  • 获取元素数量:使用size()方法获取HashMap中键值对的数量。
  • 遍历元素:可以使用keySet()方法获取所有键的集合,values()方法获取所有值的集合,或者使用entrySet()方法获取所有键值对的集合,然后使用迭代器或增强for循环进行遍历。
  • 清空HashMap:使用clear()方法清空HashMap中的所有键值对。

需要注意的是,HashMap是非线程安全的,如果在多线程环境下使用HashMap,需要进行额外的同步处理或者使用线程安全的ConcurrentHashMap。另外,HashMap的初始容量和加载因子可以影响HashMap的性能,需要根据实际情况进行合理的设置。

TreeMap 集合

TreeMap是Java中的一种有序映射集合,它是基于红黑树实现的。TreeMap提供了键的唯一性、有序性和基于红黑树的高效插入、删除和查找操作。

TreeMap的特点

  • 键的唯一性:TreeMap中的键是唯一的,不允许重复键的存在。如果插入重复键的键值对,新的值会覆盖旧的值。
  • 有序性:TreeMap中的键值对是根据键的自然顺序或自定义比较器进行排序的。默认情况下,键会按照升序排列,但也可以通过自定义比较器来实现其他排序方式。
  • 高效性:TreeMap的插入、删除和查找操作的时间复杂度为O(logN),其中N为键值对的数量。这得益于红黑树的平衡性质,使得树的高度相对较低。

TreeMap的常用方法

  • 插入键值对:使用put(key, value)方法向TreeMap中插入键值对。
  • 获取值:使用get(key)方法根据键获取对应的值。
  • 删除键值对:使用remove(key)方法根据键删除对应的键值对。
  • 查询键值是否存在:使用containsKey(key)方法判断指定的键是否存在。
  • 获取键的集合:使用keySet()方法获取所有键的集合。
  • 获取值的集合:使用values()方法获取所有值的集合。
  • 获取键值对的集合:使用entrySet()方法获取所有键值对的集合。
  • 获取首个键:使用firstKey()方法获取最小的键。
  • 获取末尾键:使用lastKey()方法获取最大的键。
  • 获取小于给定键的最接近键:使用lowerKey(key)方法获取小于给定键的最接近的键。
  • 获取大于给定键的最接近键:使用higherKey(key)方法获取大于给定键的最接近的键。
  • 截取子映射:使用subMap(fromKey, toKey)方法获取指定范围内的子映射。

总之,TreeMap是一种功能强大的有序映射集合,适用于需要按键进行排序和查找的场景。它提供了多种常用方法,方便对键值对进行操作和查询。

浅谈 LinkedHashMap 集合

LinkedHashMap是Java中的一个集合类,它是HashMap的一个子类。与HashMap不同的是,LinkedHashMap在在HashMap的基础上增加了双向链表来维护插入顺序或访问顺序。

LinkedHashMap集合具有以下特点:

  • 具有插入顺序:LinkedHashMap可以保持元素的插入顺序,即元素被放入集合中的顺序将会被保留。
  • 具有访问顺序:LinkedHashMap还可以根据元素的访问顺序来排序元素。当一个元素被访问时,它会被移动到链表的末尾,这样最近访问的元素就会排在最后。
  • 允许空键和空值:与HashMap一样,LinkedHashMap允许添加空键和空值。
  • 不是线程安全的:与HashMap一样,LinkedHashMap也不是线程安全的。如果多个线程同时访问一个LinkedHashMap,并且至少一个线程修改了集合的结构,那么必须通过外部同步来确保对其的安全访问。

LinkedHashMap提供了HashMap所具有的基本操作,如添加、删除、获取和遍历元素等。此外,它还提供了一些与顺序相关的方法,如getFirst()、getLast()、removeFirst()和removeLast()等,用于获取和删除链表的第一个和最后一个元素。

通过使用LinkedHashMap,您可以在需要保持元素插入顺序或访问顺序的场景中,更好地控制和管理集合中的元素。

Properties 集合

Properties集合是Java中用于处理属性配置信息的特殊集合类。它继承自Hashtable类,因此具有Hashtable的一些特性,如键值对的存储和查找。Properties集合的特殊之处在于它通常被用于存储应用程序的配置信息,比如数据库连接信息、系统设置等。

Properties集合中的每个键值对都是以字符串形式存储的。每个键和值都是字符串类型,因此适合存储文本相关的配置信息。键和值都是唯一的,不允许重复。

Properties集合提供了一些特有的方法来读取和写入属性配置信息。其中包括:

  • getProperty(String key):根据指定的键获取对应的值。
  • setProperty(String key, String value):将指定的键值对添加到Properties集合中,如果键已存在,则替换原有的值。
  • load(InputStream input):从输入流中读取属性配置信息,将其加载到Properties集合中。
  • store(OutputStream output, String comments):将Properties集合中的属性配置信息写入到输出流中,可以选择添加注释。

通过上述方法,可以灵活地读取和写入属性配置信息,实现动态的配置参数。Properties集合也可以迭代遍历,使用keySet()或entrySet()方法获取键或键值对的集合,然后进行处理操作。

总结:Properties集合是用于存储属性配置信息的特殊集合类,提供了读取和写入属性的方法。它继承自Hashtable类,适用于存储字符串类型的键值对。

Map 集合的遍历

使用entrySet()方法

通过调用Map的entrySet()方法,可以获取到一个包含所有键值对的Set集合,然后通过迭代器或者增强for循环遍历该Set集合,获取每一个键值对的键和值。

Map<String, Integer> map = new HashMap<>();
// 添加键值对
map.put("A", 1);
map.put("B", 2);
map.put("C", 3);
// 遍历键值对
for (Map.Entry<String, Integer> entry : map.entrySet()) {
    String key = entry.getKey();
    Integer value = entry.getValue();
    System.out.println("Key: " + key + ", Value: " + value);
}

使用keySet()方法

通过调用Map的keySet()方法,可以获取到一个包含所有键的Set集合,然后通过迭代器或者增强for循环遍历该Set集合,获取每一个键,并通过键获取对应的值。

Map<String, Integer> map = new HashMap<>();
// 添加键值对
map.put("A", 1);
map.put("B", 2);
map.put("C", 3);
// 遍历键值对
for (String key : map.keySet()) {
    Integer value = map.get(key);
    System.out.println("Key: " + key + ", Value: " + value);
}

使用values()方法

通过调用Map的values()方法,可以获取到一个包含所有值的Collection集合,然后通过迭代器或者增强for循环遍历该Collection集合,获取每一个值,但是能拿到所有的value。

Map<String, Integer> map = new HashMap<>();
// 添加键值对
map.put("A", 1);
map.put("B", 2);
map.put("C", 3);
// 遍历键值对
for (Integer value : map.values()) {
    System.out.println("Value: " + value);
}

集合嵌套

在Java中,集合的嵌套是指在一个集合中包含另一个集合。这种嵌套的方式可以用来构建更复杂的数据结构,以满足不同的业务需求。

List嵌套

可以在List集合中嵌套另一个List集合,形成一个二维列表。

示例代码:

List<List<Integer>> nestedList = new ArrayList<>();
List<Integer> innerList1 = new ArrayList<>();
innerList1.add(1);
innerList1.add(2);
List<Integer> innerList2 = new ArrayList<>();
innerList2.add(3);
innerList2.add(4);
nestedList.add(innerList1);
nestedList.add(innerList2);

Set嵌套

可以在Set集合中嵌套另一个Set集合,形成一个二维Set。

示例代码:

Set<Set<String>> nestedSet = new HashSet<>();
Set<String> innerSet1 = new HashSet<>();
innerSet1.add("apple");
innerSet1.add("banana");
Set<String> innerSet2 = new HashSet<>();
innerSet2.add("orange");
innerSet2.add("grape");
nestedSet.add(innerSet1);
nestedSet.add(innerSet2);

Map嵌套

可以在Map集合中嵌套另一个Map集合,形成一个二维Map。

示例代码:

Map<String, Map<String, Integer>> nestedMap = new HashMap<>();
Map<String, Integer> innerMap1 = new HashMap<>();
innerMap1.put("apple", 1);
innerMap1.put("banana", 2);
Map<String, Integer> innerMap2 = new HashMap<>();
innerMap2.put("orange", 3);
innerMap2.put("grape", 4);
nestedMap.put("fruits", innerMap1);
nestedMap.put("citrus", innerMap2);

以上只是几种常见的集合嵌套方式,实际上,可以根据具体的业务需求,灵活地进行集合的嵌套和组合。通过合理地使用集合的嵌套,可以构建出更复杂的数据结构,满足不同的业务场景。

Iterator 迭代器

迭代器(Iterator)是Java集合框架中的一个接口,它提供了一种遍历集合元素的统一方式。通过迭代器,我们可以按顺序访问集合中的每个元素,而不需要了解集合内部的结构。

Iterator 迭代器的常用方法

  • hasNext():判断集合中是否还有下一个元素,如果有则返回true,否则返回false。
  • next():返回集合中的下一个元素,并将迭代器的指针移动到下一个位置。
  • remove():从集合中删除迭代器最后访问的元素。

Iterator 迭代器的基本流程

  • 通过调用集合对象的 iterator() 方法获取迭代器对象。
  • 使用 hasNext() 方法判断是否还有下一个元素。
  • 如果有下一个元素,使用 next() 方法获取该元素,并进行相关操作。
  • 重复步骤 2 和步骤 3,直到遍历完所有元素。

示例代码:

List<String> list = new ArrayList<>();
list.add("Apple");
list.add("Banana");
list.add("Orange");

Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
    String element = iterator.next();
    System.out.println(element);
}

在上述代码中,我们首先通过 iterator() 方法获取到集合的迭代器,然后使用 hasNext() 和 next() 方法进行遍历,最后输出每个元素的值。

需要注意的是,一旦我们开始使用迭代器遍历集合,就不能对集合进行修改,否则会抛出ConcurrentModificationException异常。如果需要删除集合中的元素,应该使用迭代器的remove()方法。

迭代器在Java集合框架中被广泛使用,几乎所有的集合类都实现了迭代器接口,包括ArrayList、LinkedList、HashSet、TreeSet等。

Collections 类

Collections类是Java集合框架中的一个工具类,提供了一系列静态方法来操作集合对象。它包含了许多常用的方法,用于对集合进行排序、查找、替换、填充等操作。

Collections 类的常用方法

  • sort(List list): 对指定列表进行排序。使用该方法可以对List集合中的元素进行自然排序或者指定排序规则。
  • reverse(List list): 反转指定列表中元素的顺序。
  • shuffle(List list): 随机打乱指定列表中元素的顺序。
  • binarySearch(List<? extends Comparable<? super T>> list, T key): 使用二分查找算法在指定列表中查找指定元素。
  • max(Collection<? extends T> coll): 返回指定集合中的最大元素。
  • min(Collection<? extends T> coll): 返回指定集合中的最小元素。
  • frequency(Collection<?> coll, Object o): 返回指定集合中指定元素出现的次数。
  • copy(List<? super T> dest, List<? extends T> src): 将源列表中的元素复制到目标列表中。
  • fill(List<? super T> list, T obj): 使用指定的元素替换指定列表的所有元素。
  • addAll(Collection<? super T> c, T… elements): 将指定元素添加到指定集合中。

Collections类提供了许多方便的方法来操作集合对象,简化了集合的操作。通过使用这些方法,可以更加高效地处理集合中的元素。

Comparator 比较器

Comparator(比较器)是Java中一个接口,用于定义两个对象之间的比较规则。它提供了一种自定义排序的方式,可以根据自己的需求来定义对象的比较逻辑。

Comparator接口中定义了一个compare方法,用于比较两个对象的大小。这个方法接收两个参数,分别是要比较的两个对象,并返回一个整数值。

比较器的返回值规则如下:

  • 如果第一个对象小于第二个对象,则返回一个负整数。
  • 如果第一个对象等于第二个对象,则返回0。
  • 如果第一个对象大于第二个对象,则返回一个正整数。

通过实现Comparator接口,可以自定义比较器来对对象进行排序。比较器可以用于对集合中的元素进行排序,也可以用于实现自定义的数据结构或算法。

在Collections类的sort方法中,可以指定一个Comparator对象来进行排序。使用比较器可以灵活地对集合中的元素进行排序,无需修改元素的实现类或实现Comparable接口。

比较器还可以用于优先队列、树集等数据结构中,用于定义对象的优先级或排序顺序。

总之,比较器提供了一种灵活的方式来定义对象的比较规则,可以根据自己的需求来进行自定义排序。

代码示例:

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

class Student {
    private String name;
    private int age;

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }
}

class AgeComparator implements Comparator<Student> {
    @Override
    public int compare(Student s1, Student s2) {
        return Integer.compare(s1.getAge(), s2.getAge());
    }
}

public class ComparatorExample {
    public static void main(String[] args) {
        List<Student> students = new ArrayList<>();
        students.add(new Student("Alice", 20));
        students.add(new Student("Bob", 22));
        students.add(new Student("Charlie", 18));

        // 使用Comparator进行年龄排序
        Collections.sort(students, new AgeComparator());

        // 打印排序结果
        for (Student student : students) {
            System.out.println(student.getName() + " - " + student.getAge());
        }
    }
}

泛型

Java泛型是Java语言引入的一种类型安全机制,它在编译时期强制执行类型检查,以确保代码的类型安全性。泛型可以应用于类、接口、方法等,它的核心思想是参数化类型,即在定义类、接口、方法时使用类型参数,这些类型参数可以在使用时被指定具体的类型。

泛型的优点

  • 类型安全:泛型可以在编译时期进行类型检查,避免了运行时类型转换错误,提高了程序的健壮性。
  • 代码重用性:泛型可以使代码更加通用,减少了重复编写类似的代码的需求。
  • 可读性和可维护性:泛型可以提高代码的可读性,使代码更加清晰和易于理解。

使用泛型的方式

  • 类型参数:在定义类、接口、方法时使用类型参数,使用尖括号"<>"来表示,例如:List。
  • 泛型类:在类的定义中使用类型参数,用于指定类中的成员变量、方法的参数类型和返回值类型。例如:List。
  • 泛型接口:在接口的定义中使用类型参数,用于指定接口中的方法的参数类型和返回值类型。例如:Comparable。
  • 泛型方法:在方法的定义中使用类型参数,用于指定方法的参数类型和返回值类型。例如:public T method(T t)。

泛型还支持通配符和上界、下界的限定,可以进一步增加泛型的灵活性。

总之,Java泛型是一种强大的类型安全机制,可以增加代码的可读性和可维护性,提高代码的重用性和健壮性。它是Java语言中非常重要的特性之一,值得开发者深入学习和使用。

泛型的定义和使用

泛型类

泛型类允许我们在类的定义中使用类型参数,用于指定类中的成员变量、方法的参数类型和返回值类型。

示例代码:

public class Box<T> {
    private T item;

    public void setItem(T item) {
        this.item = item;
    }

    public T getItem() {
        return item;
    }
}

在上面的示例中, Box 类使用了一个类型参数 T,用于表示盒子中存放的物品的类型。setItem 方法用于设置盒子中的物品,getItem 方法用于获取盒子中的物品。

泛型接口

泛型接口允许我们在接口的定义中使用类型参数,用于指定接口中的方法的参数类型和返回值类型。

示例代码:

public interface List<T> {
    void add(T item);
    T get(int index);
}

在上面的示例中,List接口使用了一个类型参数T,用于表示列表中的元素的类型。add方法用于向列表中添加元素,get方法用于获取列表中指定索引位置的元素。

泛型方法

泛型方法允许我们在方法的定义中使用类型参数,用于指定方法的参数类型和返回值类型。

示例代码:

public class Utils {
    public static <T> void printArray(T[] array) {
        for (T item : array) {
            System.out.println(item);
        }
    }
}

在上面的示例中, printArray方法使用了一个类型参数T ,用于表示数组中的元素的类型。该方法可以接受任意类型的数组作为参数,并打印数组中的元素。

使用泛型时,我们可以通过指定具体类型来实例化泛型类、实现泛型接口,或者调用泛型方法。

示例代码:

public static void main(String[] args) {
    Box<Integer> intBox = new Box<>();
    intBox.setItem(10);
    int item = intBox.getItem();
    System.out.println(item);

    List<String> strList = new ArrayList<>();
    strList.add("Apple");
    strList.add("Banana");
    String firstItem = strList.get(0);
    System.out.println(firstItem);

    Integer[] intArray = {1, 2, 3, 4, 5};
    Utils.printArray(intArray);
}

在上面的示例中,我们创建了一个Box对象并设置了一个整数值,然后获取并输出了该值。我们还创建了一个List对象并添加了两个字符串元素,然后获取并输出了第一个元素。最后,我们调用了Utils类中的printArray方法,传入了一个整数数组,并打印了数组中的元素。

通过使用泛型,我们可以在编译时期确定集合中元素的类型,并避免类型转换错误,增加代码的类型安全性和重用性。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值