Java-- 集合
前言
相信做开发的老铁们, 不管你是做 Java,Android, 还是其他的语言, 我相信很多都遇到过集合这个名词, 而且我相信很多的老铁在进行大公司面试的时候, 一定不可避免的会被问到关于集合这个问题, 本人以前对这些基础的东西理解的非常浅, 但随着这几年的开发发现集合对于项目开发是非常重要的. 如果能合理的运用集合的几个实现类, 那么事情可能达到事半功倍的效果, 所以本人也做一些笔记巩固一下知识.
正文
首先集合的分类: Collection and Map. 但是从源码的角度去看, 发现这两个其实本不是 java 类, 而是 Java 接口, 个人觉得这就是 Java 现在面向接口编程的最忠实的写照.
Collection:
首先我们的知道 Collection 并不是我们想象中的衍生出它的实现类, 而是实现了另外的两个接口, List and Set 衍生出的这两个接口是互补的.
首先我们必须知道为什么会衍生出两个接口(两个接口的不同之处)
Set:
是无序并且是不可重复, 集合中的对象不按特定的方式排序, 只是简单地把对象加入集合中
List:
有序并且是可重复的, 里面存储的对象是有序的, 而且 List 提供了几个关于索引的方法. 查询速度快. 因为往 list 集合里插入或删除数据时, 会伴随着后面数据的移动, 所有插入删除数据速度慢.
两个接口的不同点说完了, 我们来了解一下在集合中不得不提到的一个重要的环节
循环 --------------------->平时可能大家说的遍历.
在我们这两大集合接口中不可获取的肯定是去遍历这个集合, 常用 List 的老铁们可能在平时的 List 的使用方法中用到的都是比较传统方式就是
- for(int i = 0;i <list.size();i++){
- // 处理的逻辑代码
- }
或者是高级 for 循环
for(Ob ob:obs){-------------------->这里的 ob 是我对对象的简称, 希望大家能够理解
- // 处理的逻辑代码
- }
以上的这种循环的处理方式. 但是这种方式只能适用于 List 这个接口实现遍历的方式, 那么我们的 Set 接口如何来实现遍历呢. 创造集合的大神早已想到了这一点. 所以在集合中就衍生了另外一个遍历集合的另外一个方式
Iterator------>中文名称叫迭代器.
它是专门负责集合的遍历的一个接口. 在它的基础之上, 也衍生了一个 ListIterator 这个专门为 List 专用的迭代器. 使用的方法也很简单. 首先我们必须获取到当前 List 或者是 Set 整个集合对象的迭代器, 然后对整个迭代器进行遍历. 示例代码如下:
- Iterator iterator = arr.iterator();
- while(iterator .hasNext()){
- Ob ob = iterator.next();
- }
就是这么简单容易.
下面我再来介绍一下 List 的结合相关的子类: ArrayList 和 LinkedList
ArrayList 和 LinkedList 在用法上的区别: 了解这些, 能让你在日常的开发中合理的运用相关的实现类, 来提高程序的效率. 这也是你做一些大数据处理的时候提高程序效率的一个重要的点.
1,LinkedList 经常用在增删操作较多而查询操作很少的情况下, ArrayList 则相反.
2,ArrayList 是实现了基于动态数组的数据结构, LinkedList 基于链表的数据结构.
3, 对于随机访问 get 和 set,ArrayList 绝对优于 LinkedList, 因为 LinkedList 要移动指针.
4, 对于新增和删除操作 add 和 remove,LinkedList 比较占优势, 因为 ArrayList 要移动数据. 这一点要看实际情况的. 若只对单条数据插入或删除, ArrayList 的速度反而优于 LinkedList. 但若是批量随机的插入删除数据, LinkedList 的速度大大优于 ArrayList. 因为 ArrayList 每插入一条数据, 要移动插入点及之后的所有数据.
在我复习集合的资料整理的过程中, 另外还有一个集合那就是 ------------------>Vector
首先我们通过源码知道, Vector 是矢量队列, 它继承了 AbstractList, 实现了 List, RandomAccess, Cloneable, java.io.Serializable 接口.
Vector 继承了 AbstractList, 实现了 List, 它是一个队列, 因此实现了相应的添加, 删除, 修改, 遍历等功能.
Vector 实现了 RandomAccess 接口, 因此可以随机访问.
Vector 实现了 Cloneable, 重载了 clone()方法, 因此可以进行克隆.
Vector 实现了 Serializable 接口, 因此可以进行序列化.
Vector 的操作是线程安全的.
所以这就是 Vector 具备的一些相关属性.
Vector 的数据结构和 ArrayList 差不多, 包含了 3 个成员变量: elementData,elementCount,capacityIncrement.
(1)elementData 是 Object[]的数组, 初始大小为 10, 会不断的增长.
(2)elementCount 是元素的个数.
(3)capacityIncrement 是动态数组增长的系数.
Vector 有四种遍历方式:
(1)第一种通过迭代器遍历, 即通过 Iterator 去遍历
- Integer value=null;
- Iterator iter=vector.iterator();
- while(iter.hasNext())
- {
- value=(Interger)iter.next();
- }
(2)第二种随机访问, 通过索引进行遍历
- Integer value=null;
- int size=vector.size();
- for(int i=0;i
- {
- value=vector.get(i);
- }
(3)第三种通过 for 循环的方式
- Integer value=null;
- for( Integer inte: vector)
- {
- value=inte;
- }
(4)第四种, Enumeration 遍历
- Integer value=null;
- Enumeration enu=vector.elements();
- while(enu.hasMoreElements())
- {
- value=(Integer)enu.nextElement();
- }
从上面的写法我们能够得些什么呢?
1, 首先他是一个实实在在 Java class;
2, 如果使用 Vector, 它又有了自己专属的迭代器 Enumeration.
关于 List 相关的集合类我们就介绍在这里, 下面我们来介绍一下集合中第二个很重要的重要的接口 ---->
Map
map 相信很多人都知道并且用过, map 存储数据的方式是通过键值对的方式进行存储 (key-value). 所以呢, 因为它是键值对的方式, 那么就必须要保证它的键(key) 是唯一的, 通过 key 去检索到 value(值), 值可以不是唯一, 这是它的一大特性. 接下来说一下 map 集合实现类, 然后呢通过实现类来总结一下 map 的遍历方式
map 的实现类: HashMap,Hashtable,LinkedHashMap 和 TreeMap, 这几个是常用的实现类.
HashMap
HashMap 是最常用的 Map, 它根据键的 HashCode 值存储数据, 根据键可以直接获取它的值, 具有很快的访问速度, 遍历时, 取得数据的顺序是完全随机的. 因为键对象不可以重复, 所以 HashMap 最多只允许一条记录的键为 Null, 允许多条记录的值为 Null, 是非同步的
Hashtable
Hashtable 与 HashMap 类似, 是 HashMap 的线程安全版, 它支持线程的同步, 即任一时刻只有一个线程能写 HashTable, 因此也导致了 HashTable 在写入时会比较慢, 它继承自 Dictionary 类, 不同的是它不允许记录的键或者值为 null, 同时效率较低. 所以当需要实现线程同步, 而数据量比较小时, 还是可以使用 HashTable 的
ConcurrentHashMap
线程安全, 并且锁分离. ConcurrentHashMap 内部使用段 (Segment) 来表示这些不同的部分, 每个段其实就是一个小的 hash table, 它们有自己的锁. 只要多个修改操作发生在不同的段上, 它们就可以并发进行.
LinkedHashMap
LinkedHashMap 保存了记录的插入顺序, 在用 Iteraor 遍历 LinkedHashMap 时, 先得到的记录肯定是先插入的, 在遍历的时候会比 HashMap 慢, 有 HashMap 的全部特性.
TreeMap
TreeMap 实现 SortMap 接口, 能够把它保存的记录根据键排序, 默认是按键值的升序排序(自然顺序), 也可以指定排序的比较器, 当用 Iterator 遍历 TreeMap 时, 得到的记录是排过序的. 不允许 key 值为空, 非同步的;
接下来我们讲一下 map 的遍历, 两种方式 :keySet() and entrySet()
第一种: KeySet()
将 Map 中所有的键存入到 set 集合中. 因为 set 具备迭代器. 所有可以迭代方式取出所有的键, 再根据 get 方法. 获取每一个键对应的值. keySet(): 迭代后只能通过 get()取 key .
取到的结果会乱序, 是因为取得数据行主键的时候, 使用了 HashMap.keySet()方法, 而这个方法返回的 Set 结果, 里面的数据是乱序排放的.
典型用法如下:
- Map map = new HashMap();
- map.put("key1","data1");
- map.put("key2","data12");
- map.put("key3","data123");
- map.put("key4","data1234");
- // 首先获取到 map 集合中所有键的 set 集合, keyset(), 方法如下
- Iterator it = map.keySet().iterator();
- // 获取到迭代器然后通过遍历得到 key, 然后通过 get(key)的方法得到 Object
- while(it.hasNext()){
- Object key = it.next();
- System.out.println(map.get(key));
- }
第二种: entrySet()
Set> entrySet() // 返回此映射中包含的映射关系的 Set 视图.(一个关系就是一个键 - 值 对), 就是把 (key-value) 作为一个整体一对一对地存放在 Set 集合当中. Map.Entry 表示映射关系. entrySet(): 迭代后可以 e.getKey(),e.getValue()两种方法来取 key 和 value. 返回的是 Entry 接口.
典型用法如下:
- Map map = new HashMap();
- map.put("key1","data1");
- map.put("key2","data12");
- map.put("key3","data123");
- map.put("key4","data1234");
- // 将 map 集合中的映射关系取出, 存入到 set 集合
- Iterator it = map.entrySet().iterator();
- while(it.hasNext()){
- Entry e =(Entry) it.next();
- System.out.println("键"+e.getKey () + "的值为" + e.getValue());
- }
推荐使用第二种方式, 即 entrySet()方法, 效率较高.
对于 keySet 其实是遍历了 2 次, 一次是转为 iterator, 一次就是从 HashMap 中取出 key 所对应的 value. 而 entryset 只是遍历了第一次, 它把 key 和 value 都放到了 entry 中, 所以快了. 两种遍历的遍历时间相差比较明显.
总结
集合是我们在开发中不可或缺的一个关键而且比较重要的环节, 我在复习的过程中也明白了许多自己以前还是有很多不知道的地方, 比如在前段时间可以在开发中对于 map 集合的遍历都不是很懂, 只是会写, 现在由于空闲时间比较多, 仔细的研究了一下, 还是有一种豁然开朗的赶脚. 所以希望这些东西能够给老铁们有所帮助. 最后希望所有的程序员老铁都能写出高质量的代码, 升职加薪.... 走上人生巅峰.
来源: http://www.jianshu.com/p/a670d8b5cb96