为什么使用集合
数组长度是固定,如果要改变数组的长度需要创建新的数组将旧数组里面的元素拷贝过去,使用起来不方便。
java给开发者提供了一些集合类,能够存储任意长度的对象,长度可以随着元素的增加而增加,随着元素的减少而减少,使用起来方便一些。
数组和集合的区别
区别1:
数组既可以存储基本数据类型,又可以存储引用数据类型,基本数据类型存储的是值,引用数据类型存储的是地址值。
集合只能存储引用数据类型(对象),如果存储基本数据类型时,会自动装箱变成相应的包装类。
区别2:
数组长度是固定的,不能自动增长
集合的长度的是可变的,可以根据元素的增加而自动增长
集合基础体系图
java提供了一些集合类,这些集合类分别适用于不同的场景,下面是常用的一些集合基础体系图(图片引自网络)。
Collection是接口,下面的List、Set、Queue也都是接口,并且继承了这个Collection。最下面的ArrayList、LinkedList、Vector、HashSet、TreeSet、PriorityQueue都是他们的实现类。
List:存放的数据是有顺序的,可以存放重复的数据。
LinkedList :基于链表实现,链表内存是散列的,增删快,查找慢;
ArrayList :基于数组实现,非线程安全,效率高,增删慢,查找快;
Vector :基于数组实现,效率低,增删慢,查找慢,线程安全;
Set:存放的数据是没有顺序的,不能存放重复的数据;
TreeSet:提供有序的Set集合,是自然排序,它继承了AbstractSet抽象类,相对读取慢;
HashSet :底层是由 Hash Map 实现,不允许集合有重复的值,使用该方式时需要重写 equals()和 hashCode()方法;
LinkedHashSet :继承于 HashSet,同时又基于 LinkedHashMap 来进行实现,底层使用的是 LinkedHashMap,按添加顺序排序;
Queue:是一个队列,里面的数据是先进先出,可以存放重复的数据。
Collections是针对集合类的一个帮助类。提供了一系列静态方法实现对各种集合的搜索、排序、线程完全化等操作。
例如:
Collections.max(Collection coll); 取coll中最大的元素。
Collections.sort(List list); 对list中元素排序
Map是接口,下面的HashMap、HashTable、AbstractMap也都是接口,并且继承了这个Map。最下面的LinkedHashMap、TreeMap是他们的实现类。
HashMap:里面存放的数据是没有顺序的,键值对可以存null键和null值,key 不能重复,值可重复,线程不安全。
LinkedHashMap :继承 了HashMap ,保存了记录的插入顺序;
HashTable:里面存放的元素不保证有序,key 不能重复,值可重复,线程安全。
TreeMap:基于红黑树 (red-black tree) 数据结构实现,按 key 排序,默认的排序方式是升序。
HashMap详情分析
HashMap实际上是一个“链表散列”的数据结构,即数组和链表的结合体。
HashMap的底层结构是一个数组,数组中的每一项是一条链表。
HashMap的实例有两个参数影响其性能“初始容量” 和 装填因子。
HashMap实现不同步,线程不安全,HashTable线程安全。
HashMap中的key-value都是存储在Entry中的。
HashMap可以存null键和null值,不保证元素的顺序恒久不变,通过hashCode()方法和equals方法保证键的唯一性。
hashCode()方法解决哈希冲突主要有三种方法:开放定址法,链表法,再散列法。
HashMap是采用 链表法 解决哈希冲突的。
注: 链表法是将相同hash值的对象组成一个链表放在hash值对应的槽位;
Hashtable、HashMap、ConcurrentHashMap的区别
HashMap和HashTable在功能上基本相同,但HashMap是线程不安全的,HashTable是线程安全的;
HashMap的key和value都是可以为null的,当get()方法返回null值时,HashMap中可能存在某个key,只不过该key值对应的value为null,也有可能是HashMap中不存在该key,所以不能使用get()==null来判断是否存在某个key值,对HashMap和HashTable,提供了containsKey()方法来判断是否存在某个key。
HashTable是不允许key和value为null的。HashTable中的方法大部分是同步的,因此HashTable是线程安全的。
在JDK1.5以后,出现了ConcurrentHashMap和HashTable功能很像,不允许为null的key或value,但它不是通过给方法加synchronized方法进行并发控制的。在ConcurrentHashMap中使用分段锁技术Segment,将数据分成一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,其他段的数据也能被其他线程访问,能够实现真正的并发访问。效率也比HashTable好的多。
TreeMap、HashMap、LinkedHashMap的区别
LinkedHashMap保存了数据的插入顺序,底层是通过一个双链表的数据结构来维持这个插入顺序的,key和value都可以为null。
TreeMap实现了SortMap接口,它保存的记录是根据键值key排序,默认是按key升序排列。也可以指定排序的Comparator。
HashMap、LinkedHashMap和TreeMap都是线程不安全的,提供两种遍历Map的方法如下
推荐方式
Map<String, Integer> map = new HashMap<String, Integer>(20);
//直接遍历出Entry
for(Map.Entry<String, Integer> entry : map.entrySet()){
System.out.println("key-->"+entry.getKey()+",value-->"+m.get(entry.getValue()));
}
这种方式相当于首先通过Set<Map.Entry<String,Integer>> set = map.entrySet();方式拿到Set集合,而Set集合是可以通过foreach的方式遍历的。
普通方式
Map<String, Integer> map = new HashMap<String, Integer>(20); Iterator<String> keySet = map.keySet().iterator(); //遍历Hash表中的key值集合,通过key获取value
while(keySet .hasNext()){
Object key = keySet .next();
System.out.println("key-->"+key+",value-->"+m.get(key));
}
HashSet内部使用Map保存数据,即将HashSet的数据作为Map的key值保存,这也是HashSet中元素不能重复的原因。而Map中保存key值的,会去判断当前Map中是否含有该Key对象,内部是先通过key的hashCode,确定有相同的hashCode之后,再通过equals方法判断是否相同。