Java中的集合

本文详细介绍了Java集合框架中的Collection和Map接口,包括它们的基本概念、特点以及主要实现类如ArrayList、LinkedList、HashSet、HashMap、TreeMap等的区别。重点对比了线程安全、数据结构、插入删除效率等方面,强调了不同场景下选择合适集合类的重要性,同时也提及了迭代器、快速失败机制等核心概念。
摘要由CSDN通过智能技术生成

第一章 集合概述

我们知道在集合的框架的继承树中,最顶层有两个接口,分别是Collection和Map.
Collection表示一组纯数据,而Map则表示一组键值对

Collection是最基本的集合接口,一个Collection代表一组对象,也就是Collection的元素.JDK不提供直接继承自Collection的类,JDK提供的类都是继承自Collection的子接口,比如说List和Set.

所有实现Collection接口的类都必须提供两个标准的构造函数,无参构造和有参构造,无参构造用于创建一个空的Collection,有参构造用于创建一个新的Collection,这个新的Collection与传入的Collection有相同的元素.

第二章 Collection接口的介绍

这里写图片描述

1 Collection接口下有三个子接口,分别是List,Set和Queue
2 List接口:List接口中有ArrayList,LinkedList,Vector,和Stack.我们用的比较多的是ArrayList和LinkedList,这两者的区别很明显,从名字上就能看出来.ArrayList底层通过数组实现,所以其随机访问速度比较快,但是对于频繁的增删的情况,效率就比较低了,而LinkedList,底层是通过链表来实现的,所以增删比较快,但是对于随机访效率比较低.至于Vector,他是ArrayList的线程安全版本,说到线程安全,大家估计机会想到,他的执行效率低.Stack则对应栈数据结构,Vector和Stack使用的很少,在这就不多说了
3 Set接口:Set接口表示数学意义上的集合概念.Set中不包含重复的元素,即Set中不存在两个这样的元素,使得a.equals(b)为true.由于Set接口提供数据结构是数学意义上的集合概念,因此他需要支持对象的添加,删除,而不需要提供随机访问.元素加入Set之前需要先执行hashCode()方法,如果值已经在集合中存在,则要继续执行equals()方法,如果equals方法返回的结果也为真,则证明该元素已经存在,新元素就会把旧元素覆盖.如果hashCode()返回的值不同,则直接加入集合.这里请记住一点,对于Set集合中的元素,hashCode值不同的元素一定不相等,但是不相等的元素,hashCode值可能相同.
3.1.1.1 说完Set集合的一般特性后,再来说一下Set接口下的几个子类,Set接口下有HashSet,LinkedHashSet和TreeSet.HashSet和LinkedHshSet的区别是LinkedHashSet的输出顺序和输入顺序是一致的,而HashSet则不然,对于TreeSet,默认情况下是按照字符的自然顺序进行升序排列的
4 List和Set的区别
4.1.1.1 其实他们的区别很简单,就是List在添加元素的时候,不执行额外的操作,并且可以重复,而Set在添加元素的时候需要执行hashCode方法等一系列的判断, 一句话就是List集合有序可重复,Set集合无序唯一
4.1.1.2 Set集合检索效率低,删除和插入效率高,插入和删除不会引起元素位置的变化;List集合和数组类似,List集合可以动态增长,查找元素效率高,删除和插入效率低,因为会引起元素位置的变化
5 Collection集合的遍历

常见的集合遍历方式有以下四种:

5.1 Iterator:迭代输出,是使用最多的输出方式
5.2 ListIterator:是Iterator的子接口,专门用于输出List中的内容
5.3 foreach输出:JDK1.5之后提供的新功能,可以输出数组或集合。
5.4 for循环

第三章Map接口的介绍

这里写图片描述

1 Map类型的集合存储的是键值对,键不能重复,只可以重复,根据键得到值,Map集合最大的优点在于其查找效率比较高
2 Map接口下有六个类,分别是HashMap,EnumMap,IdentityHashMap,LinkedHashMap,TreeMap,HashTable,其中最常用的是HashMap,LinkedHashMap和HashMap的区别在于LinkedHashMap的输出顺序与插入顺序一致,他们与TreeMap的区别在于TreeMap是根据键值进行排序的,当然其底层实现也是有本质区别的.HashMap的底层是一个哈希表,TreeMap的底层是一棵树,TreeMap和LinkedHashMap的区别是TreeMap是按照字符串进行输出的,而LinkedHashMap是根据插入顺序进行输出的.HashMap和TreeMap的区别和之前提到的HashSet和TreeSet的区别是一致的,其实HashSet和TreeSet本质上分别是通过HashMap和TreeMap来实现的,所以他们的区别自然也是相同的.HashTable现在已经很少使用了,与HashMap的区别是HashTable是线程安全的,由于其效率比较低.所有通常使用HashMap ,在多线程环境下,使用CurrentHashMap来代替.
3 HashMap
3.1.1 HashMap是最常用的Map集合,他根据键的HashCode值存储数据,根据键可以直接获取值,具有很快的访问速度,遍历时,取得数据的顺序是完全随机的,因为键对象不可以重复,所以HashMap最多只允许有一条记录的键为nul,允许多条记录的值为null,是非线程安全的
3.1.2 HashTable与HashMap类似,是HahMap的线程安全版,它支持线程同步,也就是说任一时刻只能有一个线程能写HashTable,因此易导致了HashTable在添加数据时比较慢,但是他不允许键或值为null
3.1.3 LinkedHashMap保存了记录插入顺序,在用Iterator遍历LinkedHashMap时,先得到的记录肯定是先插入的,在便利的时候比HashMap慢,有HashMap的全部特性
3.1.4 TreeMap实现的是SortMap接口,能够把保存的记录按照键排序,默认是按键值得升序排序(自然顺序),当用Iteator遍历TreeMap时,得到的记录是排过序的,他不允许键值为空,不是线程安全的
4 Map的遍历
4.1 KeySet()方式

将Map中的所有键存到Set集合中.因为Set具备迭代器,所以可以迭代取出所有的键,再根据get方法,获取每一个键对应的值.取到的结果是乱序的,这是因为使用了HashMap.keySet()方法,而这个方法返回Set集合,所以是乱序的

Map map = new HashMap();
map.put("key1","lisi1");
map.put("key2","lisi2");
map.put("key3","lisi3");
map.put("key4","lisi4");  
//先获取map集合的所有键的set集合,keyset()
Iterator it = map.keySet().iterator();
 //获取迭代器
while(it.hasNext()){
Object key = it.next();
System.out.println(map.get(key));
}
4.2 EntrySet()方式

Set< Map,Entry < K,V > >就是把(key-value)作为一个整体一对一的存放到Set集合中entrySet迭代后可以e.getKey()获取键,和e.getValue()获取值,返回的Entry接口
典型用法如下:

Map map = new HashMap();
map.put("key1","lisi1");
map.put("key2","lisi2");
map.put("key3","lisi3");
map.put("key4","lisi4");
//将map集合中的映射关系取出,存入到set集合
Iterator it = map.entrySet().iterator();
while(it.hasNext()){
Entry e =(Entry) it.next();
System.out.println("键"+e.getKey () + "的值为" + e.getValue());
}

推荐使用第二种方式,因为效率比较高,因为对于keySet其实是遍历了两次,一次是转为iterator,一次就是从HashMap中取出可以对应的value.而EntrySet只是遍历了一次,把key和value都放到了entry中,所以效率更高

第五章 主要实现类区别

Vector和ArrayList
1,vector是线程同步的,所以它也是线程安全的,而arraylist是线程异步的,是不安全的。如果不考虑到线程的安全因素,一般用arraylist效率比较高。
2,如果集合中的元素的数目大于目前集合数组的长度时,vector增长率为目前数组长度的100%,而arraylist增长率为目前数组长度的50%。如果在集合中使用数据量比较大的数据,用vector有一定的优势。
3,如果查找一个指定位置的数据,vector和arraylist使用的时间是相同的,如果频繁的访问数据,这个时候使用vector和arraylist都可以。而如果移动一个指定位置会导致后面的元素都发生移动,这个时候就应该考虑到使用linklist,因为它移动一个指定位置的数据时其它元素不移动。
ArrayList 和Vector是采用数组方式存储数据,此数组元素数大于实际存储的数据以便增加和插入元素,都允许直接序号索引元素,但是插入数据要涉及到数组元素移动等内存操作,所以索引数据快,插入数据慢,Vector由于使用了synchronized方法(线程安全)所以性能上比ArrayList要差,LinkedList使用双向链表实现存储,按序号索引数据需要进行向前或向后遍历,但是插入数据时只需要记录本项的前后项即可,所以插入数度较快。
arraylist和linkedlist
1.ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。
2.对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedList要移动指针。
3.对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据。 这一点要看实际情况的。若只对单条数据插入或删除,ArrayList的速度反而优于LinkedList。但若是批量随机的插入删除数据,LinkedList的速度大大优于ArrayList. 因为ArrayList每插入一条数据,要移动插入点及之后的所有数据。
HashMap与TreeMap
1、 HashMap通过hashcode对其内容进行快速查找,而TreeMap中所有的元素都保持着某种固定的顺序,如果你需要得到一个有序的结果你就应该使用TreeMap(HashMap中元素的排列顺序是不固定的)。
2、在Map 中插入、删除和定位元素,HashMap是最好的选择。但如果您要按自然顺序或自定义顺序遍历键,那么TreeMap会更好。使用HashMap要求添加的键类明确定义了hashCode()和 equals()的实现。
两个map中的元素一样,但顺序不一样,导致hashCode()不一样。
同样做测试:
在HashMap中,同样的值的map,顺序不同,equals时,false;
而在treeMap中,同样的值的map,顺序不同,equals时,true,说明,treeMap在equals()时是整理了顺序了的。
HashTable与HashMap
1、同步性:Hashtable是线程安全的,也就是说是同步的,而HashMap是线程序不安全的,不是同步的。
2、HashMap允许存在一个为null的key,多个为null的value 。
3、hashtable的key和value都不允许为null。

第六章 常在核心Java面试中问到

1、什么是Iterator

  一些集合类提供了内容遍历的功能,通过java.util.Iterator接口。这些接口允许遍历对象的集合。依次操作每个元素对象。当使用 Iterators时,在获得Iterator的时候包含一个集合快照。通常在遍历一个Iterator的时候不建议修改集合本省。

2、Iterator与ListIterator有什么区别?

  Iterator:只能正向遍历集合,适用于获取移除元素。ListIerator:继承Iterator,可以双向列表的遍历,同样支持元素的修改。

3、什么是HashMap和Map?

  Map是接口,Java 集合框架中一部分,用于存储键值对,HashMap是用哈希算法实现Map的类。

4、HashMap与HashTable有什么区别?对比Hashtable VS HashMap
两者都是用key-value方式获取数据。Hashtable是原始集合类之一(也称作遗留类)。HashMap作为新集合框架的一部分在Java2的1.2版本中加入。它们之间有一下区别:
● HashMap和Hashtable大致是等同的,除了非同步和空值(HashMap允许null值作为key和value,而Hashtable不可以)。
● HashMap没法保证映射的顺序一直不变,但是作为HashMap的子类LinkedHashMap,如果想要预知的顺序迭代(默认按照插入顺序),你可以很轻易的置换为HashMap,如果使用Hashtable就没那么容易了。
● HashMap不是同步的,而Hashtable是同步的。
● 迭代HashMap采用快速失败机制,而Hashtable不是,所以这是设计的考虑点。
5、在Hashtable上下文中同步是什么意思?

  同步意味着在一个时间点只能有一个线程可以修改哈希表,任何线程在执行hashtable的更新操作前需要获取对象锁,其他线程等待锁的释放。

6、什么叫做快速失败特性
从高级别层次来说快速失败是一个系统或软件对于其故障做出的响应。一个快速失败系统设计用来即时报告可能会导致失败的任何故障情况,它通常用来停止正常的操作而不是尝试继续做可能有缺陷的工作。当有问题发生时,快速失败系统即时可见地发错错误告警。在Java中,快速失败与iterators有关。如果一个iterator在集合对象上创建了,其它线程欲“结构化”的修改该集合对象,并发修改异常 (ConcurrentModificationException) 抛出。
7、怎样使Hashmap同步?
HashMap可以通过Map m = Collections.synchronizedMap(hashMap)来达到同步的效果。
8、什么时候使用Hashtable,什么时候使用HashMap
基本的不同点是Hashtable同步HashMap不是的,所以无论什么时候有多个线程访问相同实例的可能时,就应该使用Hashtable,反之使用HashMap。非线程安全的数据结构能带来更好的性能。
如果在将来有一种可能—你需要按顺序获得键值对的方案时,HashMap是一个很好的选择,因为有HashMap的一个子类 LinkedHashMap。所以如果你想可预测的按顺序迭代(默认按插入的顺序),你可以很方便用LinkedHashMap替换HashMap。反观要是使用的Hashtable就没那么简单了。同时如果有多个线程访问HashMap,Collections.synchronizedMap()可以代替,总的来说HashMap更灵活。
9、为什么Vector类认为是废弃的或者是非官方地不推荐使用?或者说为什么我们应该一直使用ArrayList而不是Vector
你应该使用ArrayList而不是Vector是因为默认情况下你是非同步访问的,Vector同步了每个方法,你几乎从不要那样做,通常有想要同步的是整个操作序列。同步单个的操作也不安全(如果你迭代一个Vector,你还是要加锁,以避免其它线程在同一时刻改变集合).而且效率更慢。当然同样有锁的开销即使你不需要,这是个很糟糕的方法在默认情况下同步访问。你可以一直使用Collections.sychronizedList来装饰一个集合。
事实上Vector结合了“可变数组”的集合和同步每个操作的实现。这是另外一个设计上的缺陷。Vector还有些遗留的方法在枚举和元素获取的方法,这些方法不同于List接口,如果这些方法在代码中程序员更趋向于想用它。尽管枚举速度更快,但是他们不能检查如果集合在迭代的时候修改了,这样将导致问题。尽管以上诸多原因,oracle也从没宣称过要废弃Vector。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值