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集合的遍历都不是很懂,只是会写,现在由于空闲时间比较多,仔细的研究了一下,还是有一种豁然开朗的赶脚。所以希望这些东西能够给老铁们有所帮助。最后希望所有的程序员老铁都能写出高质量的代码,升职加薪。。。。走上人生巅峰。