集合的好处

之前保存多个数据的时候一直都是用的数组,但是数组

  1. 长度开始时必须指定,而且一旦指定,不能更改
  2. 保存的必须为同一类型的元素
  3. 使用数组进行增加/删除元素时比较麻烦

但是集合避免了这些缺点,可以动态保存任意多个对象。

常用的集合主要可以分为两类

  1. 单列集合Collection
    • List:ArrayList、LinkedList、Vector
    • Set:HashSet、TreeSet
  2. 双列集合Map:HashMap、TreeMap、Hashtable、Properties

Collection

Collection是一个接口,不可以实例化。该类提供了一些通用方法,供实现该接口的类使用。

  1. size:集合中元素个数
  2. isEmpty:检查集合是否为空
  3. clear:清空集合

List

List实现了Collection接口,除了通用方法外,还含有:

  1. add(i,b):把b元素添加到集合的i位置
  2. addAll(i,b):从i位置开始,把b中所有元素添加进来
  3. get(i):得到i位置上的元素
  4. indexOf(a)/lastIndexOf(a):返回a在List中第一次/最后一次出现的位置
  5. remove(i):移除并返回i位置上的元素
  6. set(i,a):将位置i上的元素替换成a
  7. subList(i,j):返回集合下标[i,j)的子集

ArrayList的扩容机制:当实例化对象时,可以指定大小。如果使用的无参构造器,则初始化大小为0,添加元素时,扩容为10。无论是否指定了初始大小,如果需要再次扩容,则每次扩充为原大小的1.5倍。

Vector的扩容机制:当实例化对象时,可以指定大小。如果使用无参构造器,则初始化大小为10。如果需要扩容则按照两倍扩容。

Vector相比于ArrayList效率较低,但是Vector在源码中添加了synchronized修饰,保证了线程安全,因此在开发中,需要线程同步安全时,要考虑Vector。

LinkedList:本质是双向链表,具有双向链表的一切特性,头尾部增删很快,改查很慢,不适合改查操作多的环境。

Set

集合内元素唯一,且不能通过索引查找,遍历顺序不能保证与插入顺序一致。可以使用addremove方法。

HashSet

  • HashSet的底层是HashMap
  • 添加一个元素时,先得到hash值,使用hash值转化成索引值
  • 找到存储数据表table,看这个索引位置是否有已经存放的元素,如果没有就加入,如果有并且元素不同(使用equals比较),就添加到最后
  • 在jdk8中,如果一条链表长度超过TREEIFY_THRESHOLD(默认是8),并且table大小≥MIN_TREEIFY_CAPACITY(默认是64),就会变成红黑树。
  • 第一次添加元素时,table数组扩容到16,临界值=threShold*loadFactor=最大长度*0.75=16*0.75=12
  • 如果数组长度到了临界值,就会再次进行扩容,容量=当前最大长度*2,直到达到了树化条件,新的临界值=最大长度*0.75
  • 如果想保证元素的遍历顺序等于插入顺序,可以使用LinkedHashSet

TreeSet

TreeSet是即有序集合,底层基于红黑树,能够确保集合元素按照升序或降序排列。

相比于HashSet新增的方法有:

  1. firse/last:获取第一个/最后一个元素
  2. floor(a)/ceiling(a):获取小于等于/大于等于a的最大/最小元素

Map

Map与Collection并列存在,用于保存具有映射关系的数据:键值对。Map中的key和value可以是任何引用类型的数据,会封装到HashMap$Node对象中。

Map接口常用方法:

  1. put(key, value):添加键值对
  2. remove():根据键删除映射关系
  3. get(key):根据键获取值
  4. size:获取元素个数
  5. isEmpty:判断Map是否为空
  6. clear:清空
  7. containsKey:查找键是否存在
  8. keySet:返回所有键的集合

HashMap键值对的两种遍历方法:

public class Test{
public Map<String, Integer> hashMap = new HashMap<>();
public static void main(String[] args){
// 1.遍历键,找到值
for (String key: hashMap.keySet()){
int value = hashMap.get(key);
System.out.println(key + ": " + value);
}
// 2.使用entrySet获取键值对
for (Map.Entry<String, Integer> entry : hashMap.entrySet()) {
String key = entry.getKey();
int value = entry.getValue();
System.out.println(key + ": " + value);
}
}
}

HashMap没有实现同步,不保证线程安全。

HashTable与HashMap使用的方法基本一致,区别在于:

  1. HashTable的键和值都不能为null,否则会报空指针异常
  2. HashTable是线程安全的,多个线程不能同时修改HashTable中的内容
  3. HashTable在性能上比HashMap略差

Properties类是用于处理属性文件的类,继承自HashTable类,并实现了Map接口,特点与HashTable类似。Properties主要用于从properties文件中加载数据到Properties类对象,并进行读取和修改。

方法:

  1. setProperty(key, value):添加属性
  2. getProperty(key):获取属性
  3. load:加载属性文件
  4. store:保存属性文件

TreeMap即有序键值对,可以保证插入的键有序排列,方法与HashMap大致相同,但是TreeMap不允许键为null,只允许值接null。

Collections工具类

Collections是一个操作Set、List、Map等集合的工具类,其中提供了一系列的static方法对元素进行排序、查询和修改等操作。

主要方法:

  1. sort:对List进行升序排序,其中可以编写比较器对List指定排序方法
  2. shuffle:打乱List中元素的顺序
  3. reverse:对List进行翻转
  4. swap:交换List中两个元素的位置
  5. max/min:返回集合中最大/最小的元素
  6. frequency(Collection, Object):返回Collection集合中Object的出现次数