java集合
4.集合类简介
数组是很常用的一种的数据结构,我们用它可以满足很多的功能,但是,有时我们会遇到如下这样的问题:
1、我们需要该容器的长度是不确定的。
2、我们需要它能自动排序。
3、我们需要存储以键值对方式存在的数据。
如果遇到上述的情况,数组是很难满足需求的,接下来本章将介绍另一种与数组类似的数据结构——集合类,集合类在Java中有很重要的意义,保存临时数据,管理对象,泛型,Web框架等,很多都大量用到了集合类。
常见的集合类有这些种:(集合是否重复,判断元素的hashcode和equals判断)
实现Collection接口的:Set、List以及他们的实现类。
Map集合:HashMap和TreeMap
他们的关系如下:
|
接口
|
简述
|
实现
|
操作特性
|
成员要求
|
|
Set
|
成员不能重复
|
HashSet
|
外部无序地遍历成员
|
成员可为任意Object子类的对象,但如果覆盖了equals方法,同时注意修改hashCode方法。
|
|
TreeSet
|
外部有序地遍历成员;附加实现了SortedSet, 支持子集等要求顺序的操作,建议HashSet插入删除,再转型成TreeSet
|
成员要求实现caparable接口,或者使用 Comparator构造TreeSet。成员一般为同一类型。
|
||
|
LinkedHashSet
|
外部按成员的插入顺序遍历成员
|
成员与HashSet成员类似
|
||
|
List
|
提供基于索引的对成员的随机访问
|
ArrayList
|
提供快速的基于索引的成员访问,对尾部成员的增加和删除支持较好
|
成员可为任意Object子类的对象
|
|
LinkedList
|
对列表中任何位置的成员的增加和删除支持较好,但对基于索引的成员访问支持性能较差,数组和链表的组合
|
成员可为任意Object子类的对象
|
||
|
Map
|
保存键值对成员,基于键找值操作,compareTo或compare方法对键排序
|
HashMap
|
能满足用户对Map的通用需求
|
键成员可为任意Object子类的对象,但如果覆盖了equals方法,同时注意修改hashCode方法。
|
|
TreeMap
|
支持对键有序地遍历,使用时建议先用HashMap增加和删除成员,最后从HashMap生成TreeMap;附加实现了SortedMap接口,支持子Map等要求顺序的操作
|
键成员要求实现caparable接口,或者使用Comparator构造TreeMap。键成员一般为同一类型。
|
||
|
LinkedHashMap
|
保留键的插入顺序,用equals 方法检查键和值的相等性,数组和链表的组合
|
成员可为任意Object子类的对象,但如果覆盖了equals方法,同时注意修改hashCode方法。
|
||
|
IdentityHashMap
|
使用== 来检查键和值的相等性。
|
成员使用的是严格相等
|
||
|
WeakHashMap
|
其行为依赖于垃圾回收线程,没有绝对理由则少用
|
|
二、基本方法及使用
- Collection使用
void add(E e) 加入集合
void addAll(Collection c) 加入所有的集合对象
boolean containsAll(Collection c)是否包括集合的所有对象
void remove(E e) 移除集合
void removeAll(Collection c) 移除所有的集合对象
void clear() 清空集合的对象
boolean isEmpty() 是否为空
int size() 集合的个数
toArray(T[l.size()] a) 返回一个数组
toArray()返回一个包含此Collection中所有元素的Object类型数组;
Iterator iterator() 返回一个迭代器
↓
boolean hasNext()→ Object next() 记得强转→如果不能通过集合的remove()就用迭代器的remove(),之前先next()
iterator相当于有个箭头指在第一个元素之前,next之后就会返回刚经过的元素,这时箭头指在第一个和第二个之间,remove同样的必须先next,删除刚经过的元素。
同一个集合循序多个迭代器读取元素,但不允许多个迭代器同时修改元素。会抛异常。
-
Collection集合遍历方法
-
:
-
使用foreach循环 要求对象实现iterable接口
-
使用迭代器
-
List集合(能重复)数组能用下标
-
实现类:ArrayList 和LinkedList ,前者访问速度快,但是插入删除慢,后者相反 List<E> list = new ArrayList<E>();
-
在Cllection接口基础上增加如下方法:
-
E get(int dex)和E set(int dex,Object b)List转换成数组:list.toArray(new String[list.size()]) 传入转换后相同的类型数组转换成List:Arrays.asList() 不能对其增删,不然抛出异常remove(int index)移除指定位置上的元素。(还有很多其他重载方法)
-
List的排序
-
Comparable接口中有int campareTo(T t)方法,集合的元素如果实现了接口就可以调用Collections.sort(T t)方法实现自然递增排序,导致sort方法对我们的类有较强的侵入性。Public class A implements Comparable<A>{Public int CompareTo(A a){return >0 大 =0 相等 <0 小}}推荐使用:自定义排序方法:
-
方式一:通过自定义一个类实现Comparator接口,实现Comparator接口的int compare(T t1,T t2)方法,传入对象进行自定义排序。调用Collections.sort(T t,com)
-
方式二:使用匿名内部类更好
-
Collections.sort(T t,new Comparator<T>(){public int compare(T t1,T t2){return 1,0,-1;}})它的好处在于:
-
不要求对象实现了comparable接口,
-
有些元素已经实现了comparable接口并且定义了比较规则,但是不满足要求的,也可以用额外的比较器来定义规则满足要求。
-
LinkedListt是一个双向链表,实现了队列(Queue接口)可以将队列看成特殊的线性表,队列限制了对线性表的访问方式:只能从线性表的一端添加(offer)元素,从另一端取出(poll)元素,队列遵循先进先出(FIFO First Input First Output )的原则。Queue extends Collection接口,另增方法如下:
-
boolean offer(E e):将元素追加到队列末尾,若添加成功则返回true。E poll():从队首删除并返回该元素。E peek():返回队首元素,但是不删除。综合:LinkedList遍历就增加一种方法:
-
使用循环poll()方法。While(e.poll()!=null)
-
Pop pollFirst poll
-
Offer offerLast
-
Deque是Queue的子接口,定义了所谓“双端队列”即从队列的两端分别可以入队(offer)和出队(poll),LinkedList实现了该接口。如果将Deque限制为只能从一端入队和出队,则可实现“栈”(Stack)的数据结构,对于栈而言,入栈称之为push,出栈称之为pop。栈遵循先进后出(FILO First Input Last Output )的原则。
|
pollLast
offerFirst push
|
-
首先看这两类都实现List接口,而List接口一共有三个实现类,分别是ArrayList、Vector和LinkedList。List用于存放多个元素,能够维护元素的次序,并且允许元素的重复。3个具体实现类的相关区别如下:
- ArrayList是最常用的List实现类,内部是通过数组实现的,它允许对元素进行快速随机访问。数组的缺点是每个元素之间不能有间隔,当数组大小不满足时需要增加存储能力,就要讲已经有数组的数据复制到新的存储空间中。当从ArrayList的中间位置插入或者删除元素时,需要对数组进行复制、移动、代价比较高。因此,它适合随机查找和遍历,不适合插入和删除。
- Vector与ArrayList一样,也是通过数组实现的,不同的是它支持线程的同步,即某一时刻只有一个线程能够写Vector,避免多线程同时写而引起的不一致性,但实现同步需要很高的花费,因此,访问它比访问ArrayList慢。
- LinkedList是用链表结构存储数据的,很适合数据的动态插入和删除,随机访问和遍历速度比较慢。另外,他还提供了List接口中没有定义的方法,专门用于操作表头和表尾元素,可以当作堆栈、队列和双向队列使用。
Set集合(不能重复,且加入的元素必须实现了Comparable接口)
-
实现类:HashSet(哈希表,不保证顺序不变)和 TreeSet
-
TreeSet还实现了java.util.SortedSet类,TreeSet可以按照自然顺序递增或者比较器递增,所以增加的方法有如下:
new TreeSet(); Set的元素实现了Comparable接口,按自然排序
new TreeSet(new Comparator(){}) 如果自然排序不满足条件,可以自定义排序,这里是使用匿名内部类。
-
first() Set集合的第一个对象Last() Set集合的最后一个对象tailSet( E e) Set集合中e(包括)之后的对象headSet( E e) Set集合中e(不包括)之前的对象subSet(E e1,E e2)返回不包含e2的实现Set接口的视图对象
-
-
Map集合
-
含义:Map没有继承Collection接口,提供key value的键值对,key不能重复(equals判断),如果key值已存在,将会替换value值
-
实现类:(hash表)HashMap和(二叉树)TreeMap(底层采用红黑树)
-
区别:前者哈希表,查找迅速但顺序不是不变,后者相反,后者还实现了java.util.sortedMap接口。
-
Hash表
-
原理:HashMap内部维护着一个散列数组(就是一个存放元素的数组),每个列表都是一个桶,我们称其为散列桶,而当我们向HashMap中存入一组键值对时,HashMap首先获取key这个对象的hashcode()方法的返回值,得出一个数字,再对桶总数取余,这个数字就是这组键值对要存入散列数组中的下标位置。桶为空就加进去,不为空就用equals()查看散列数组的链表里是否已经包含这个对象,HashMap会将每组键值对封装为一个Entry的实例,然后将该实例存入链表,否则就替换value。那么在获取元素时,HashMap同样先根据key的hashcode值进行散列算法,找到它在散列数组中的位置,然后遍历该位置的链表,找到该key所对应的value之后返回。HashMap 的实例有两个参数影响其性能:初始容量16 和加载因子(默认0.75). 达到16*0.75=12时,map扩容一倍成32.
但是当位于一个桶中的元素较多,即hash值相等的元素较多时,通过key值依次查找的效率较低。jdk7中采用数组+链表,而JDK1.8中,哈
希表存储采用数组+链表+红黑树实现,当链表长度超过阈值(8)时,将链表转换为红黑树,这样大大减少了查找时间
-
-
方法:
-
void put(K key,V value) 加入对象如果在Map中重新存入以有的key,那么key的位置会不会发生改变,只是将value值替换。object get(K key) 返回对象 没有key就返回Nullboolean containsKey(K key) 是否包括boolean containsValue(Object o)isEmpty() 如果此映射未包含键-值映射关系,则返回 true。Void clear() 清空所有键值对size() 返回此映射中的键-值映射关系数Set keySet() 返回一个key的set接口的视图 不是hashset treeset,是某个实现了set的类Collection values()返回value的集合视图(不常用)
-
遍历Map的三种方式(上面的三种方法)
-
遍历所有的key keySet()遍历每一组键值对(Entry)遍历所有的value(不常用)
-
TreeMap:实现了SortedMap接口,所以映射根据其键的自然顺序进行排序,或者根据创建映射时提供的 Comparator 进行排序,具体取决于使用的构造方法:元素顺序固定
-
new TreeMap(); 自然new TreeMap(Comparator) 比较器
- SortedMap中有subMap()返回视图 headMap() tailMap()方法
-
线程安全:List、Set、Map都不是线程安全。调用Collections.synchronizedList()synchronizedSet()synchronizedMap()实现线程安全.
-
就算是线程安全的集合,也不与迭代器的遍历互斥,但是迭代器在遍历集合时不能通过集合增删元素,否则会抛出异常
HashMap 是 Hashtable 的轻量级实现(非线程安全的实现),他们都实现了 Map 接口,主要区别在于 HashMap 允许空(null)键值(key),由于非线程安全,效率上高于 Hashtable。HashMap 允许将 null 作为一个 entry 的 key 或者 value,而 Hashtable 不允许。HashMap 把 Hashtable 的 contains 方法去掉了,改成 containsvalue 和 containsKey。因为 contains 方法容易让人引起误解。Hashtable 继承自 Dictionary 类,而 HashMap 是 Java1.2 引进的 Map interface 的一个实现。最大的不同是, Hastable 的方法是 synchronize 的,而 HashMap 不是,在多个线程访问 Hashtable 时,不需要自己为 它的方法实现同步,而 HashMap 就必须为之提供同步。Hashtable使用枚举类型遍历。他的hash值是直接使用对象的hash值,而hashmap是重写了hash的计算。hashtable数组的默认大小极其增长方式不同。
几种视图:
可修改:列表支持set方法
可改变大小:支持add remove方法。
普通试图:subList() SortedSet接口的subSet() headSet() tailSet() SortedMap接口的subMap() headMap() tailMap() 对视图的操作会导致对原集合的操作影响。
Array.asList(a);把数组变成集合,能遍历查看,可以修改,但不能改变大小,
不可修改视图:当视图修改视图的内容,比如add remove,会抛异常 如Array.asList(s) 底层会调用collections的方法返回视图。
同步视图:collections的方法可以把不同步的集合编程多线程同步的。
检查视图:调用Collections的方法。List<String> l=new ArrayList<>();List ll=l;ll.add(2);不会报错,Collections.checkedList(l);之后再add这就会报错。

浙公网安备 33010602011771号