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方法,传入了一个整数数组,并打印了数组中的元素。
通过使用泛型,我们可以在编译时期确定集合中元素的类型,并避免类型转换错误,增加代码的类型安全性和重用性。