什么是集合?
集合是java中提供的一种存放数据的容器。即:集合与数组一样,可以保存一组元素,并提供操作元素的相关方法。
数组与集合区别
集合长度可变,数组长度不可变。因此当要存储元素的个数确定时可以使用数组,元素的个数不确定时用集合。
集合可存储不同类型元素,数组存储只可单一类型元素
集合只能存储引用类型元素,数组可存储引用类型,也可存储基本类型
Collection接口
Collection是个java.util下的接口,它是各种集合结构的父接口,提供了关于集合的一些操作,如插入、删除、判断一个元素是否其成员、遍历等。如下图:
Collection接口中的常用方法:
boolean add(E e) //向集合中添加一个元素。集合更改则添加成功返回true
void clear() //清空掉集合中的所有元素
boolean remove(Object o) //删除集合中的指定的元素。如果存在NULL,也删除。
boolean contains(Object o) //如果集合中包含指定元素那么返回true。
int size() //返回该集合中元素的个数。
boolean isEmpty() //如果集合中没有元素则返回true。
...
List与Set
由上图可知,Collection接口下有三个子接口List、Set、Queue。其中以Set接口和List接口使用最为广泛。
List:
在List中,元素存入的顺序和取出的顺序一致,元素可以重复,可以插入多个null元素,元素都有索引。
list可以根据元素的索引来对元素进行增删等操作,其具体方法有:
get(int index,E e) 获取指定位置的元素;
remove(int index) 移除指定位置的元素;
add(int index,E e) 将元素添加到指定位置;
set(int index,E e) 用元素替换指定位置的元素
List接口常用的实现类有:ArrayList、LinkedList 、Vector。
ArrayList:底层数据结构是数组,查询快,增删慢,线程不安全,效率高,可以存储重复元素
LinkedList:底层数据结构是链表,查询慢,增删快,线程不安全,效率高,可以存储重复元素
Vector:底层数据结构是数组,查询快,增删慢,线程安全,效率低,可以存储重复元素
数组结构增删慢的原因
数组是一个有序列表 ,数组是在连续的位置上面储存对象的,当我们在某个位置增加一个元素或删除某一个元素的时候,该元素之后的元素都要往后移。而数组初始化时长度是固定的,当数组长度达到最大值时若向增加元素,就必须创建一个新数组,把原数组的元素复制进来,随后原数组销毁。元素增删时的移动以及新数组的创建会消耗时间,因此增删慢。
链表查询慢的原因
链表采用动态内存分配的方式,各元素的储存地址是不连续的,也没有相应的索引,创建链表时无需考虑链表的长度;在对链表中的元素进行增删时,不需要向数组那样移动之后的元素,这也使得链表的增删效率优于数组。正因如此,如果想要访问链表中的某个元素,则需要从头遍历,无法通过索引的方式进行数据访问,查询效率自然就慢了。
Set:
在Set中,元素存入和取出顺序有可能不一致,不可以存储重复元素,只允许存入一个null元素,必须保证元素唯一性。
Set接口常用的实现类有:HashSet、LinkedHashSet、TreeSet
HashSet:底层数据结构是哈希表(数组+单向链表+红黑树),当链表长度超过阈值(8)时,链表将转换为红黑树,查询快,元素无序,元素不可重复,没有索引,线程不安全,效率高,可以存储null元素
LinkedHashSet:LinkedHashSet集合继承HashSet集合,底层数据结构采用链表和哈希表(数组+单向链表+红黑树)共同实现,链表保证了元素的顺序与存储顺序一致,哈希表保证了元素的唯一性。线程不安全,效率高。
TreeSet:底层是基于TreeMap来实现的,所以底层结构也是红黑树,元素唯一,查询快;TreeSet和HashSet不同的是不需要重写hashCode()和equals()方法,因为它去重是依靠比较器来去重,因为结构是红黑树,所以每次插入都会遍历比较来寻找节点插入位置,如果发现某个节点的值是一样的那就会直接覆盖。
总结:
List与Set的取舍
1.如果想容器中的元素能够进行有序存储,则使用List,因为 List 是一个有序容器,它按照插入顺序进行存储。
2.如果想保证插入元素的唯一性,去掉重复值的出现,那么可以选择一个 Set 的实现类,比如 HashSet、LinkedHashSet 或者 TreeSet
3.在List集合中,如果想频繁的对元素进行增删操作,则可以选择LinkedList。如果要频繁的对查询数据,则可以使用ArrayList。