一、什么是集合
在java中,集合是一个容器,是一个载体,可以一次容纳多个对象(数组便是一个集合);集合不能存放基础数据类型(8个),也不能直接存放对象,它里面存放的都是对象的引用。不同的集合底层对应着不同的数据结构,例如:数组,链表,二叉树,哈希表...
二、集合的分类
java中集合按照存储元素的方式可以分为两大类:1.单个方式存储元素的集合;2.以key和value键值对方式存储元素的集合
三、以单个方式存储元素的集合(Collection)
这类集合的超级父接口是:java.util.Collection
关系图如下
因为Collection继承Iterable接口,所以下面的实现类都自带迭代器(用于遍历)。以下介绍每个接口或实现类的特点以及底层对应的数据结构
1.List
List是一个接口类,它的存储特点是元素存储进去后的顺序不会发生改变,且可以存储重复的元素(也叫做:有序可重复)。其原因是,List集合每存放一个元素,会给该元素一个对应的下标,起始下标从0开始,每次递增1;所以区别存入的元素靠的是该元素的下标。。
1)ArrayList
ArrayList是List的实现类,其特点是:有序,可重复,有下标,非线程安全。底层是Object数组实现,所以查询效果极高但随机增删效率低。ArrayList初始化容量是10,每次扩容是原先容量的1.5倍(所以尽量少扩容)
2)LinkedList
LinkedList也是List的实现类,其特点是:有序,可重复,非线程安全。其底层是由一个双向链表实现,所以随机增删效率高,查询效率低。
3)Vector
Vector也是List的实现类,其特点是:有序,可重复,有下标,线程安全。其底层实现也是数组,但因为它是线程安全的(源码中大量方法带有synchronized),所以执行效果较低,比较少用。初始容量也是10。
2.Set
Set集合因为存储的元素并没有下标,所以其特点的是:无序(元素存入后顺序会发生改变),不可重复。
1)HashSet
HashSet是Set的实现类,特点是无序不可重复,其底层实现是HashMap,值存入HashMap中的key位置。
2)TreeSet
TreeSet实现了NavigableSet,NavigableSet实现了SortedSet,SortedSet实现了Set接口,所以说TreeSet是Set的间接实现类;TreeSet特点是:无序不可重复但能将存入的元素自动排序。其底层实现是TreeMap,值存入TreeMap中的key位置。
3.迭代器的使用
继承Iterable接口的,可以调用.iterator()方法可以得到一个迭代器,迭代器初始指向第一个元素的前一位;在Iterator接口中有两个方法.hasNext()和.next(),.hasNext()判断迭代器指向的位置是否还有下一个元素,如果有返回true,没有返回false; .next()使迭代器指向后一位元素,并返回指向的元素。
则使用迭代器遍历集合中的元素就如下:
List<String> list = new ArrayList<>();
list.add("小李");
list.add("小张");
list.add("小唐");
list.add("小王");
list.add("小徐");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
输出结果如下:
四、以键值对方式存储元素的集合(Map)
这类集合的超级父接口是:java.util.Map
关系图如下:
所有的Map集合中的key都是无序,不可重复的;这和Set集合存储元素特点相同。
1.HashMap
HashMap是Map接口的实现,底层是由哈希表(数组+单向链)构成,在JDK1.8之后新增了如果单向链的长度超过8,则单向链的结果会变成红黑树;但红黑树的节点数少于6时,又会从红黑树变成单向链。是非线程安全的,key值不能重复,允许key和value的值为null,每次扩容都是原容量的两倍。
对于存储在HashMap的key位置的自定义类,必须要重写hashCode()和equals()方法,因为要是哈希表数列分布均匀。
2.Hashtable
Hashtable是Map接口的实现,底层是由哈希表(数组+单向链)构成,是线程安全的,key值不能重复,且不允许key和value的值为null,同样每次扩容都是原容量的两倍。
3.TreeMap
TreeMap是Map接口的间接实现类,底层是自平衡二叉树,它的key值同样是无序且不可重复,但key值在存储的过程中可以自动按大小顺序排列,自平衡二叉树遵循左小右大的原则存放数据,遍历时采用中序遍历(左根右,这里的前,中,后指的是根的位置)。
对于存储在TreeMap的key位置的自定义类,因为要实现排序功能,所有必须要定义一个规则来对自定义类的两个对象进行大小比较,方法有两种:
1.自定义类实现Comparable接口,通过实现compareTo()方法,在里面规定自定义类如何比大小。
2.写一个工具类去实现Comparator接口,通过实现compare()方法,来规定自定义类如何比大小。
五、集合工具类(java.util.Collections)
具体方法看官方api,这里提一下的目的是不用将Collection接口和Collections给搞混了。