【学习笔记】Java笔记5:集合

180 阅读6分钟

1. Collection接口

1.1 相关介绍

  • 单列集合,存储一个一个的对象

  • 常用方法如下

    接口中的方法解释
    boolean contains(Object o)判断集合是否包含o对象,判断过程会调用o.equals(),所以最好重写equals方法
    boolean containsAll(Collection<?> c)判断集合c是否存在于当前集合中
    boolean remove(Object o)移除集合中的元素
    boolean removeAll(Collection<?> c)移除当前集合与集合c的交集
    boolean retainAll(Collection<?> c)求当前集合与集合c的交集,当前集合内容会被交集覆盖
    Object[] toArray()集合转换为数组
    Iterator<E> iterator()返回Iterator的实例,用于遍历Collection集合元素
  • 使用Arrays.asList()可将数组装换为List集合

  • 涉及到contains(),remove(),retainAll()等方法时,集合的元素要重写equals()方法

1.2 Iterator接口

  迭代器,常用于遍历Collection,不包括Map。

public class Test {
    public static void main(String[] args) {
        Collection coll = new ArrayList();
        coll.add(123);
        coll.add(456);
        coll.add(789);
        // 可以理解为返回了一个指向“首元素的上一个空间”的指针
        Iterator iterator = coll.iterator();
        // hanNext()判断下一个空间是否有元素
        while (iterator.hasNext()) {
            // next()方法会执行两个步骤
            // 1.指针下移
            // 2.返回指针指向的元素
            System.out.println(iterator.next());
        }
    }
}

1.3 List接口

1.3.1 相关介绍

  • 存储有序可重复的数据

1.3.2 常见实现类的比较

  • ArrayList:线程不安全,效率高,使用Object[]实现存储;是List接口的主要实现类,建议创建时就确定好大小,避免频繁扩容

    1、在Java 7 中,创建时先默认创建长度为10的Object[],扩容时扩大为原来的1.5倍;

    2、在Java 8 中,创建时的Object[]是空的,第一次调用add()方法才创建长度为10的数组,扩容时也是扩大为原来的1.5倍。

  • LinkedList:使用双向链表实现存储;对于频繁的插入和删除操作,使用该类比ArrayList效率高

  • Vector:线程安全,效率低,使用Object[]实现存储,少用

1.3.3 List接口常用方法

方法解释
boolean add(E e)向集合的尾部添加指定的元素
void add(int index, E element)在集合的指定位置插入指定元素
boolean addAll(Collection c)把指定集合的所有元素加入到当前集合的尾部
boolean addAll(int index, Collection c)把指定集合的所有元素加入到当前集合的指定位置
int indexOf(Object o)返回指定元素第一次出现的位置,没有则返回-1
int lastIndexOf(Object o)返回指定元素最后出现的位置,没有则返回-1
Object remove(int index)移除指定位置的元素,并返回该元素
Object set(int index, Object o)替换指定位置的元素,并返回被替换的旧元素
List subList(int fromIndex, int toIndex)获取左闭右开区间的子集合

1.4 Set接口

1.4.1 相关介绍

  • 存储无序不可重复的数据;

  • 无序性:以HashSet为例,元素的存储位置不是按照数组的索引顺序。底层是通过数组和链表(横向的数组,纵向的链表)来实现。

  • 不可重复性: 添加的元素会通过哈希值和调用equals()来方法判断是否重复,步骤如下

    1、通过哈希值计算在数组的位置(注:位置相同不代表哈希值相同);

    2、若该位置没元素,直接添加到这个位置;若该位置已有元素,则判断两者的哈希值是否相同;

    3、若哈希值也相同,则调用equals()方法判断;

    4、若equals()判断也是返回真,说明这两个元素相同,新元素不会添加;

    5、若上述任一判断返回假,说明这两个元素不相同,则新元素添加到旧元素所在的链表中。

    综上所述,元素会成功添加的三种情况是

    • 位置没有元素
    • 哈希值不同
    • equals()判断返回假
  • 对于放在Set中的对象,其对应的类要重写equals()和hashCode()

1.4.2 常见实现类的比较

  • HashSet:常用实现类;线程不安全,可以存储null;是由HashMap实现
  • LinkedHashSet:是HashSet的子类;遍历该类时可以按添加的顺序遍历,是因为给每个元素都添加了两个引用指针,分别指向上一个元素和下一个元素
  • TreeSet:添加的元素都是同一个类的对象,可以按照添加元素的指定属性进行排序。通过比较器来排序,即对象要实现Comparable接口,或者把Comparator实现类放入TreeSet的构造器中。底层使用红黑树

2. Map接口

2.1 相关介绍

  • 双列集合,存储一对(key - value)键值对,一对键值对是一个Entry对象

  • 由于key是无序不可重复的,所以key用Set存储。比如HashMap的key是由HashSet来存储,那么key所应对的类要重写hashCode()和equals()方法

  • value是无序可重复的,当涉及containsKey(Object key)等方法时,value对应的类要重写equals()方法

2.2 常见实现类的比较

  • HashMap:线程不安全,效率高,可以存储null的key和value

    1、Java 8 前,使用数组和链表实现

    • 实例化后,默认创建长度为16的Entry数组
    • 使用put()方法添加时,通过key的哈希值来计算位置,添加步骤类似HashSet的。最后如果equals()方法返回真,则新的value会替换旧的value
    • 超出临界值时扩容,扩大为原来的2倍,并复制旧数组的数据到新数组中

    2、Java 8 使用数组,链表以及红黑树实现

    • 使用的是Node数组,并非Entry数组
    • 首次调用put()方法时才会创建长度为16的数组
    • 当某位置的链表长度大于8且数组长度大于64时,该位置的链表改为红黑树
  • Hashtable:线程安全,效率低,不可以存储null的key和value

  • LinkedHashMap:是HashMap的子类,可以按添加的顺序遍历,原因是又加了两个引用before和after;频繁地遍历时,效率比HashMap高

  • TreeMap:添加的键值对可以按照key排序(实现Comparable接口或把Comparator实现类放进构造器中),底层使用红黑树

  • Properties:常用于处理配置文件,键值都是String类型

2.3 Map接口常用方法

方法解释
V put(K key, V value)替换一个键值对,返回旧的value
V remove(Object key)移除一个键值对,返回被移除的value
void clear()移除所有键值对
V get(Object key)获取指定key对应的value
boolean containsKey(Object key)判断是否包含指定的key
boolean containsValue(Object value)判断是否包含指定的value
boolean isEmpty()判断Map集合是否为空
Set<K> keySet()获取key集合
Collection<V> values()获取value集合
Set<Map.Entry<K,V>> entrySet()获取Entry集合

3. Collections工具类

  操作List,Set,Map的工具类。

方法解释
static void reverse(List<?> list)反转List的顺序
static void shuffle(List<?> list)随机改变List的顺序
static <T extends Comparable<? super T>> void sort(List<T> list)让List按升序排序
static void swap(List<?> list, int i, int j)交换List中两个指定位置的元素
static <T> T max(Collection<? extends T> coll, Comparator<? super T> comp)按指定比较器获取最大值
static <T> T min(Collection<? extends T> coll, Comparator<? super T> comp)按指定比较器获取最小值
static <T> List<T> synchronizedList(List<T> list)获取一个线程安全的List
static <K,V> Map<K,V> synchronizedMap(Map<K,V> m)获取一个线程安全的Map,原理是每个对象维护一个锁,然后在各方法外面套一个同步代码块