概述
Java.util包中提供了一些集合类,这些集合又被称为容器。提到容器又会想到数组,那集合与数组之间的区别是?
集合与数组的区别:数组的长度是固定的,集合的长度是可变的;数组既可以存储基本数据类型,也可以存储引用数据类型,而集合只能存储引用数据类型;数组只能存储同一类的元素,而集合可以存储多种类型的元素。
可变长度数组的原理:
当元素超出数组长度,会产生一个新数组,将原数组的数据复制到新数组中,再将新的元素添加到新数组中。
ArrayList:是按照原数组的50%延长。构造一个初始容量为 10 的空列表。
Vector:是按照原数组的100%延长。
常用的集合有List集合,Set集合以及Map集合。其中List集合和Set集合继承了Collection接口,各接口还提供了不同的实现类。
Collection接口
Collection接口是层次结构中的根接口(单列集合的根接口)。构成Collection的单位称为元素,Collection接口通常不能直接使用,但该接口提供了添加元素,删除元素,管理数据的方法。由于List接口和Set接口都是继承了Collection接口,所以这些方法对List集合和Set集合都通用。
Collection接口的常用方法
方法 | 功能描述 |
add(E e) | 将指定的对象添加到该集合中 |
remove(Object o) | 将指定的对象从该集合中移除 |
isEmpty() | 返回boolean值,判断当前集合是否为空 |
iterator() | 返回在此Collection的元素上进行迭代的迭代器,用于遍历集合中的对象 |
size() | 返回int值,获取集合中元素的个数,即集合长度 |
List集合与Set集合的区别是:List集合有序(元素存入集合的顺序与取出的顺序一致),有索引,可以存储重复元素;Set集合无序(元素存入与取出的顺序可能不一致),无索引,不可以存储重复元素,必须保证元素的唯一性。
在集合中,使用迭代器iterator来遍历集合,获取集合当中的元素。
例如:
List集合
List集合包括List接口以及List接口所有的实现类。List集合中的元素允许重复,各元素的顺序就是对象插入时的顺序,用户可以通过使用索引(元素在集合中的位置)来访问集合中的元素。
List接口
List接口继承了Collection接口,因此包含了Collection接口中的所有方法,除此之外还有新定义方法:
方法 | 功能描述 |
get(int index) | 获取指定索引位置的元素 |
set(int index,Object o) | 将集合中指定索引位置的对象修改为指定对象 |
addAll(index,collection) | 在指定的索引位插入一堆元素 |
int indexOf(obj) | 获取指定元素第一次出现的索引位,如果该元素不存在返回-1 |
int lastIndexOf(Object o) | 反向索引指定元素的位置 |
List subList(start,end) | list集合特有的迭代器 |
注意:对于List集合,底层判断元素是否相同,其实都是使用元素自身的equals方法完成的,所以建议元素都重新复写equals方法,已建立元素对象自己比较相同的条件依据。
List接口的实现类
List接口的实现类包括ArrayList , LinkedList ,Vector。
ArrayList
ArrayList类实现了可变的数组,允许保存所有元素,包括null,并可以根据索引位置对集合中的元素进行快速随机访问,但由于其是指定位置来插入或删除对象,所以ArrayList增删速度慢。
ArrayList的底层数据结构是数组,线程不同步,由于底层是数组结构,而数组结构的元素在堆内存中是连续分配的,且有索引,所以查询快,增删慢。
LinkedList
LinkedList类采用链表结构保存对象。这种结构的优点是便于向集合中插入和删除对象,但查询速度慢,线程不同步。
ListedList底层是相互引用的节点组成的双向链表,当要把数据插入到该链表的某个位置时,该数据就会被组装成一个新的节点,然后只需要改变链表中要插入位置的前后的节点引用,是他们指向新的节点,即可完成插入。删除操作同样原由,只需改变节点引用即可完成。
LinkedList集合的特有方法
方法 | 功能描述 |
addFirst | 将元素添加到链表的开头位置 |
addLast | 将元素添加到链表的结尾位置 |
offerFirst(jdk1.6以后) | 将元素添加到链表的开头位置 |
offerLast(jdk1.6以后) | 将元素添加到链表的结尾位置 |
getFirst | 获取链表中第一个元素,如果链表为空,则抛出NoSuchElementException |
getList | 获取链表中最后一个元素,如果链表为空,则抛出NoSuchElementException |
peekFirst(jdk1.6以后) | 获取链表中第一个元素,如果链表为空,则返回null |
peekLast(jdk1.6以后) | 获取链表中最后一个元素,如果链表为空,则返回null |
removeFirst | 获取链表中第一个元素,但会删除链表第一个元素,如果链表为空,则抛出NoSuchElementException |
removeLast | 获取链表中最后一个元素,但会删除链表最后一个元素,如果链表为空,则抛出NoSuchElementException |
pollFirst(jdk1.6以后) | 获取链表中第一个元素,但会删除链表第一个元素,如果链表为空,则返回null |
pollLast(jdk1.6以后) | 获取链表中最后一个元素,但会删除链表最后一个元素,如果链表为空,则返回null |
Vector
Vector底层同样是数组结构,但是由于其线程同步,执行效率低,已经被ArrayList取代。
Set集合
Set集合中的对象不按特定的方式排序,只是简单的把对象加入到集合中,但是Set集合中不能包含重复对象。Set集合由Set接口和Set接口的实现类组成,Set接口继承了Collection接口,所以包含其所有方法。
Set接口
Set接口的实现类有HashSet,LinkedHashSet,TreeSet。
HashSet
HashSet底层是哈希表结构,线程不安全,存储取出效率高,运行速度快,但是存入与取出的顺序不一致。
HashSet集合保证元素的唯一性原理:通过元素的hashCode方法,和equals方法完成的。
当元素的hashCode值相同时,才继续判断元素的equals是否为true。如果为true,那么视为相同元素,不存。如果为false,那么存储。如果hashCode值不同,那么不判断equals,从而提高对象比较的速度。
哈希表的原理:
1,对对象元素中的关键字(对象中的特有数据),进行哈希算法的运算,并得出一个具体的算法值,这个值 称为哈希值。
2,哈希值就是这个元素的位置。
3,如果哈希值出现冲突,再次判断这个关键字对应的对象是否相同。如果对象相同,就不存储,因为元素重复。如果对象不同,就存储,在原来对象的哈希值基础 +1顺延。
4,存储哈希值的结构,我们称为哈希表。
5,既然哈希表是根据哈希值存储的,为了提高效率,最好保证对象的关键字是唯一的。
这样可以尽量少的判断关键字对应的对象是否相同,提高了哈希表的操作效率。
LinkedHashSet
LinkedHashSet继承了HashSet,是具有可预知顺序的集合,它基于哈希表与链表实现的,线程不安全,运行速度快,保证了元素的存入与取出的顺序。
TreeSet
TreeSet类不仅实现类Set接口,还实现了java.util.SortedSet接口,因此TreeSet类实现Set集合在遍历时按照自然顺序或定制顺序排序。
用于对Set集合进行元素的指定顺序排序,需要依据元素自身具备的比较性。如果元素自身不具备比较性,那么在运行时则会发生异常。所以需要实现comparable接口,复写compareTo()方法,强制让元素具备比较性。依据compareTo的返回值,确定元素在TreeSet中的位置。
TreeSet方法保证元素唯一性的方式:就是参考比较方法的结果是否为0,如果return 0,视为两个对象重复,不存。
TreeSet集合排序有两种方式,Comparable和Comparator区别:
1:让元素自身具备比较性,需要元素对象实现Comparable接口,覆盖compareTo方法。
2:让集合自身具备比较性,需要定义一个实现了Comparator接口的比较器,并覆盖compare方法,并将该类对象作为实际参数传递给TreeSet集合的构造函数。
第二种方式较为灵活。
Map集合
Map集合没有继承Collection接口,其提供的是Key到Value的映射,Map中不能包含相同的key,每个key只能映射到一个value。Key还决定了存储对象在映射中的存储位置,但不是有key本身对象决定,而是由一种“散列技术”进行处理的,产生一个散列码的整数值。散列码通常用作一个偏移量,该偏移量对应分配给映射的内存区域的起始位置,从而确定存储对象在映射中的存储位置。Map集合包括Map接口以及Map接口的所有实现类。
Map集合存储和Collection有着很大不同:
Collection一次存一个元素;Map一次存一对元素。
Collection是单列集合;Map是双列集合。
Map中的存储的一对元素:一个是键,一个是值,键与值之间有对应(映射)关系。
特点:要保证map集合中键的唯一性。
Map接口
Map接口提供了将key映射到值的对象,一个映射不能包括重复的key,一个Key最多映射到一个值。
Map集合中允许值对象是null,而且没有限制,如:map.put(“05”,null)
Map接口中的方法
方法 | 功能描述 |
put(key, V value) | 向集合中添加指定的key与value的映射关系 |
containsKey(Object key) | 如果此映射包含指定的key的映射关系,则返回true |
containsValue(Object value) | 如果此映射将一个或多个key映射到指定值,则返回true |
get(Object key) | 如果存在指定的key对象,则返回该对象对应的值,否则返回null |
KeySet() | 返回该集合中所有key对象,形成set集合 |
values() | 返回该集合中所有值对象形成Collection集合 |
Map接口的实现类
Map接口的实现类有:Hashtable,HashMap,TreeMap,LinkedHashMap
HashMap
HashMap类是基于哈希表数据结构的Map接口实现,此实现提供所有可选的映射操作,并允许使用null值和null键,但必须保证键的唯一性。HashMap通过哈希表对其内部的映射关系进行快速查找。此类不保证映射的顺序,特别是他不保证该顺序恒久不变,线程不同步。
Hashtable
Hashtable底层是哈希表数据结构,是线程同步的。不可以存储null键,null值。且在jdk1.2以后,Hashtable被HashMap取代,但其子类properties仍被使用。
TreeMap
TreeMap不仅实现了Map接口,还实现了java.util.SortedMap接口,因此,集合中的映射关系具有一定的顺序。但在添加,删除和定位映射关系时,TreeMap类比HashMap类性能稍差。由于TreeMap类实现的Map集合中的映射关系是根据键对象按照一定的顺序排列的,所以不允许键对象为null。
可以通过HashMap类创建Map集合,当需要顺序输出时,在创建一个相同映射关系的TreeMap类实例,进行输出。
LinkedHashMap
在继承HashMap的同时,保证了迭代的顺序。
使用集合的技巧:
看到Array就是数组结构,有角标,查询速度很快。
看到link就是链表结构:增删速度快,而且有特有方法。addFirst; addLast; removeFirst(); removeLast(); getFirst();getLast();
看到hash就是哈希表,就要想要哈希值,就要想到唯一性,就要想到存入到该结构的中的元素必须覆盖hashCode,equals方法。
看到tree就是二叉树,就要想到排序,就想要用到比较。
比较的两种方式:
一个是Comparable:覆盖compareTo方法;
一个是Comparator:覆盖compare方法。
LinkedHashSet,LinkedHashMap:这两个集合可以保证哈希表有存入顺序和取出顺序一致,保证哈希表有序。
集合什么时候用?
当存储的是一个元素时,就用Collection。当存储对象之间存在着映射关系时,就使用Map集合。
保证唯一,就用Set。不保证唯一,就用List。
集合操作工具类:Collections
静态方法:
Collections.sort(list);//list集合进行元素的自然顺序排序。
Collections.sort(list,new ComparatorByLen());//按指定的比较器方法排序。
class ComparatorByLen implements Comparator<String>{
public int compare(String s1,String s2){
int temp = s1.length()-s2.length();
return temp==0?s1.compareTo(s2):temp;
}
}
Collections.max(list); //返回list中字典顺序最大的元素。
int index = Collections.binarySearch(list,"zz");//二分查找,返回角标。
Collections.reverseOrder();//逆向反转排序。
Collections.shuffle(list);//随机对list中的元素进行位置的置换。
将非同步集合转成同步集合的方法:Collections中的 XXX synchronizedXXX(XXX);
List synchronizedList(list);
Map synchronizedMap(map);
原理:定义一个类,将集合所有的方法加同一把锁后返回。
Collection 和 Collections的区别:
Collections是个java.util下的类,是针对集合类的一个工具类,提供一系列静态方法,实现对集合的查找、排序、替换、线程安全化(将非同步的集合转换成同步的)等操作。
Collection是个java.util下的接口,它是各种集合结构的父接口,继承于它的接口主要有Set和List,提供了关于集合的一些操作,如插入、删除、判断一个元素是否其成员、遍历等。