Java容器概述
Java容器包括两个部分:Collection和Map。
Collection:表示单个元素对象的集合,主要包括Set和List两个接口,Set表示无序,不可重复的集合,List表示有序,可重复的集合。Collection接口包含Set和List两个子接口,具体实现类有HashSet,ArrayList和LinkedList。
Map:表示键值对对象的集合。Map接口具体实现类有HashMap。
List
List表示有序,可重复的集合。List接口包括ArrayList和LinkedList实现类。
常用方法:
ArrayList<E>
底层使用数组实现,所以查询效率高,增删效率低。由于数组的长度是有限的,但是ArrayList可以存放任意数量的对象,长度不受限制,它的本质是通过定义新的更大的数组,将旧数组中的内容拷贝到新数组来实现扩容。ArrayList的Object数组初始化长度为10,如果我们存储满了这个数组,需要存储第11个对象,就会定义新的长度更大的数组,并将原数组内容和新的元素一起加入到新数组中。
LinkedList<E>
底层使用双向链表实现,所以查询效率低,增删效率高。双向链表也叫双链表,它的每个数据节点中都有两个指针,分别指向前一个节点和后一个节点,每个节点包括三部分:前一个节点,本节点信息,后一个节点。其示意图如下:
Set
Set表示无序,不可重复的集合。Set接口包括HashSet实现类。
HashSet<E>
HashSet采用哈希算法实现,底层实际是用HashMap实现 的(HashSet本质就是一个简化版的HashMap),因此查询效率和增删效率都比较高。HashSet集合其实就是HashMap的key集合,由于HashMap的定义即是key不重复的集合,所以HashSet也是无需,不可重复的集合。
Map
Map是由一些列键值对组成的组合,提供了key到value的映射。在Map中保证了key和value之间的一一对应关系,即一个key对应一个value,不能存在相同的key值,可以存在相同的value值。
常用方法:
HashMap<K,V>
底层实现采用了哈希表,这是一种非常重要的数据结构。哈希表的基本结构就是“数组+链表”,数组占用空间连续,寻址容易,查询速度快,但是增加和删除效率非常低;链表占用空间不连续,寻址困难,查询速度慢,但是增加和删除效率非常高。所以,将数组和链表的优点结合就是哈希表。其结构示意图如下:
HashMap存储数据的步骤,首先根据key对象的hashcode()方法获得hashcode,将获得的hashcode带入到哈希函数中,计算出hash值(在[0,数组长度-1]的区间中),根据hash值判断在数组中存储的位置,若对应的数组索引位置为空,则直接将数据存储到数组中;若对应的数组索引位置不为空,则将数据存储到该位置的链表末端。其存储示意图如下:
Java容器遍历
遍历List方法一:普通for循环
List<String> list = new ArrayList<String>();
for(int i=0;i<list.size();i++){
System.out.println(list.get(i));
}
遍历List方法二:增强for循环(使用泛型!)
List<String> list = new ArrayList<String>();
for(String s : list){
System.out.println(s);
}
遍历List方法三:使用Iterator迭代器(1)
List<String> list = new ArrayList<String>();
//hasNext():判断是否仍有元素可以迭代,若有则返回true
//next():返回指针指向的元素,并将指针向下移动
for(Iterator<String> iter=list.iterator(); iter.hasNext();){
System.out.println(iter.next());
}
遍历List方法四:使用Iterator迭代器(2)
List<String> list = new ArrayList<String>();
Iterator<String> iter = list.iterator();
while(iter.hasNext()){
System.out.println(iter.next());
}
遍历Set方法一:增强for循环
Set<String> set = new HashSet<String>();
for(String s : set){
System.out.println(s);
}
遍历Set方法二:使用Iterator迭代器(1)
Set<String> set = new HashSet<String>();
for(Iterator<String> iter=set.iterator();iter.hasNext();){
System.out.println(iter.next());
}
遍历Set方法三:使用Iterator迭代器(2)
Set<String> set = new HashSet<String>();
Iterator<String> iter = set.iterator();
while(iter.hasNext()){
System.out.println(iter.next());
}
遍历Map方法一:根据key获取value
Map<String,String> map=new HashMap<String,String>();
Set<String> set=map.keySet();
for(Iterator<String> iter=set.iterator();iter.hasNext();){
String s=iter.next();
System.out.println(s+"---------"+map.get(s));
}
遍历Map方法二:使用entrySet
Map<String,String> map = new HashMap<String,String>();
Set<Entry<String, String>> set=map.entrySet();
for(Iterator<Entry<String, String>> iter=set.iterator();iter.hasNext();){
Entry<String,String> e=iter.next();
System.out.println(e.getKey()+"----------------------"+e.getValue());
}
HashMap与HashTable的区别与联系:
联系:
HashMap和HashTable的底层都采用了哈希表的结构(数组+链表)
区别:
(1)继承的父类不同,HashMap继承自AbstractMap类,而HashTable继承自Dictionary类
(2)线程安全性不同,HashMap是线程不安全的,HashTable是线程安全的,每个方法中都加入了synchronized关键字。但是使用同步锁的保护机制,也会影响读写效率。
(3)key和value是否允许null值,HashMap中key和value都可以是null值,并且null值作为key只允许一个存在,而null值作为value允许存在多个;HashTable中key和value都不允许出现null值,若在HashTable中插入null值的键值对,编译可以通过,但是在运行时会发生空指针异常。
TreeMap与TreeSet的区别与联系:
联系:
TreeSet底层是通过TreeMap来实现的(类似于HashSet底层是通过HashMap来实现的),而TreeMap底层是通过红黑树来实现的。
区别:
(1)TreeMap底层采用红黑树,完成数据有序的插入和删除