集合从概念上来看就是一堆元素放在一块儿,咱们其实可使用数组来处理这样的状况(操做一堆数据),可是数组存在各类各样的限制,使用起来并不方便,所以才推出更强大的集合处理方式,即集合框架html
数组的问题:java
容器最基本的功能就是存储数据,取出数据,可是由于实际需求不一样,好比是否有序,是否可重复,不一样的数据结构,不一样的存取效率等等缘由,系统提供了一众不一样特性的容器类,共同构成了集合框架算法
框架体系结构:api
其中Collection接口支持(单个形式)数据的存储,而Map接口支持对键值对形式的数据的存储数组
ps: 因为其内部使用数组,而数组容量是固定的,这就致使了,添加删除时都会引起数组的重建,以及数据的拷贝,数据结构
举个例子:火焰山终于下雨了,刚开始觉得只下一点点,因此找了一个杯子装,后来发现装不下了,要换一个盆(建立更大的数组),那么须要先把杯子里的水倒进盆里(数据拷贝)并发
适用于:读取,查询操做更频繁的场景框架
ps:因为使用的链表结构,因此添加删除时仅须要在任意内存保存数据而后将指针添加到上一个数据的结尾便可,因此这添加删除数据时比使用数组的ArrayList快不少 ,可是当须要查找数据时,就须要频繁的移动指针(地址不是连续的),形成了查询速度慢,ide
举个例子: 你是要找王老板作生意,可是你本身不认识他,因而你就找了刘老板,刘老板也不认识他,因而刘老板找了李老板,还好最后李老板认识王老板,找到了你要找的人,期间不能跨越中间的必须一个一个找下去学习
适用于:添加,删除操做更频繁的建立
能够说HashSet就是对HashMap进行了简单的包装:
真正存储数据的容器:
包装后的添加数据的方法:
iterable叫作可迭代对象
咱们知道集合框架提供了不少不一样的容器实现类,可是每种容器的内部实现不一样,致使咱们须要记忆不一样的取值方法,这对于使用者来讲无疑增长学习成本,因此Java统一了各类容器的取值方式,即经过iterable接口
public Iterator iterator();//用于返回一个迭代器接口对象
Iterator叫作迭代器
迭代器用于获取容器中的值
public boolean hasNext(); //判断是否还有下一个 public Integer next();//获取下一个的值
使用案例:
//写一个支持foreach语法的类 import java.util.Iterator; public class MyTest implements Iterable<Integer> { private int num = 0; @Override public Iterator<Integer> iterator() { return new Iterator<Integer>() { @Override public boolean hasNext() { return num < 11; } @Override public Integer next() { return num++; } }; } //测试: public static void main(String[] args) { for (Integer i:new MyTest()) { System.out.println(i); } } } //该类能够迭代获得0-10这11个数字
ps:collection接口继承了iterable,因此全部collection的子类能够被foreach遍历
咱们可使用foreach来遍历collection的任何子类对象:
案例:
HashSet<String> set = new HashSet<String>(); set.add("1"); set.add("2"); set.add("3"); ArrayList<String> list = new ArrayList<String>(); list.add("1"); list.add("2"); list.add("3"); for (String s: list) { System.out.println(s); } for (String s: set) { System.out.println(s); }
须要特别强调的是不容许在迭代期间删除或添加元素,将会引起:java.util.ConcurrentModificationException
异常,意思是不容许并发修改
那么咱们如何删除元素呢?
//删除或添加单个元素: ArrayList<String> list = new ArrayList<String>(); list.add("1"); list.add("2"); list.add("3"); for (String s: list) { list.add("11111"); break;//操做完成后直接break; } //删除或添加多个元素方法1 //先保存须要删除的元素,迭代完成在一并删除 ArrayList<Integer> list = new ArrayList<Integer>(); list.add(1); list.add(2); list.add(3); ArrayList deletes = new ArrayList(); for (Integer i: list) { if (i > 1){ deletes.add(i); } } list.removeAll(deletes); //删除或添加多个元素方法2 //使用lambda表达式 jdk1.8以后可用 list.removeIf(i -> i > 1); //删除或添加多个元素方法3 //迭代copy的集合,从原始集合删除 for (Integer i: (ArrayList<Integer>)list.clone()) { if(i > 1){ list.remove(i); } } //删除或添加多个元素方法4 //使用迭代器 Iterator<Integer> iterator = list.iterator(); while (iterator.hasNext()){ if (iterator.next() > 1){ iterator.remove(); } }
//HashMap,不是Collection的子类因此不能直接foreach //可用使用下面几种方式: //方法1 for ( String key: map.keySet()) { System.out.println(key+" "+map.get(key)); } //方法2 for (Map.Entry entry:map.entrySet()){ System.out.println(entry.getKey() +" "+entry.getValue()); }
HashMap内部使用hash表(本质是一个数组见图一)
HashMap使用hash算法计算获得存放的索引位置,一次来加快查询速度,(比ArrayList还要快)
hash值相同不能表示key彻底相同,须要调用equals再次确认
若是说key的hash值相同可是equals判断不相同,那么使用树结构或者链表来存储这些hash相同的元素,(具体使用哪一种根据当前map中元素的数量,超过64个元素则使用树结构)
代码在putVal方法的最后,当添加元素后的大小超过阈值时则直接扩容hash表
总结:
HashMap是使用Hash表(本质是数组)来存储数据,
当keyHash值相同可是equals判断不一样时使用链表(添加快,查询慢)
当元素数量超过64时则将链表转为数结构(添加慢,查询快)
最后再来一张框架图,帮助理解:
图中的Listiterator 能够实现倒叙迭代,须要的话咨询查询API