简介
java集合包括两大接口:collection接口和Map接口。
collection接口介绍
collection是最基本的集合接口,java SDK不提供直接继承collection,而java SDK提供的类继承自collection接口,如:List接口和Set接口。
List接口
List接口是有序的collection,List是有序的,可以使用索引(类似于数组的下标)来访问List中的元素,与Set不同的是,List允许有重复的数据。
collection和List都是接口,不是类,所以只能用ArrayList等实现类去实例化,而:
List l = new List();
Collection c = new Collection();
是编译错误的,若是:
List l = new ArrayList();
Collection c = new ArrayList();
则是可以的。
Collection常用的方法:
boolean add(Object o) 向集合中添加对象
boolean addAll(Collection c) 将集合c中所有的元素添加到集合中
void clear() 删除集合中所有元素
boolean contains(Object o) 判断元素o是否在集合中,若存在返回true,否则false
boolean containsAll(Collection c) 判断集合中是否包含集合c中所有元素
boolean isEmpty() 判断集合是否为空
Iterator iterator() 返回该集合的迭代器
Collection c = new ArrayList();
c.add("abc");
c.add("abc");
c.add("abc");
Iterator i = c.iterator();
while(i.hasNext()){
System.out.println(i.next()); }
结果:
abc
abc
abc
boolean remove(Object o) 如果存在元素o就删除,返回true,否则返回false,若有多个重复的,例如有3个abc,一个remove只会删掉一个abc,还剩下2个。
注意特殊情况:
如果list内有5个字符串“123”,
for (int i = 0; i < list.size(); i++) {
if (((String) list.get(i)).startsWith("1")) {
list.remove(i);
}
运行后list的size不是0,而是2,这是因为List每remove掉一个元素以后,后面的元素都会向前移动,此时如果执行i=i+1,则刚刚移过来的元素没有被读取。
解决方法:
1.倒过来遍历list
for (int i = list.size()-1; i > =0; i--) {
if (((String) list.get(i)).startsWith("1")) {
list.remove(i);
}}
2.每移除一个元素以后再把i移回来
for (int i = 0; i < list.size(); i++) {
if (((String) list.get(i)).startsWith("1")) {
list.remove(i);
i=i-1;
}}
3.使用iterator.remove()方法删除
for (Iterator it = list.iterator(); it.hasNext();) {
String str = (String)it.next();
if (str.equals("123")){
it.remove();
}}
boolean removeAll(Collection c) 将该集合中,只要是c中存在的,全部删除。
boolean retainAll(Collection c) 与removeAll相反,将该集合中,只要c不存在的,全部删除,只留下c中存在的元素。
int size() 返回集合的大小,即集合中元素的个数
Object[] toArray() 将集合中的元素以数组的形式返回,返回类型是Object
Object[] toArray(Object[] a) 返回集合中所有元素的数组,返回数组的运行时类型与指定数组的运行时类型一致。
List常用方法:
list继承了Collection所有方法,并且有一些新增的方法:
Object get(int index) 返回索引值为index的元素
List subList(int fromIndex,int toIndex) 返回新的List,元素为原来List的第fromIndex个,到第toIndex个,但不包括最后的第toIndex个元素。
int indexOf(Object o) 在集合中查找元素o,若存在,返回找到的第一个元素所在的索引值,若不存在,返回-1。
int lastIndexOf(Object o) 与indexOf类似,只不过返回的是匹配到的最后一个元素的索引值。
Object set(int index,Object o) 将第index个元素,替换为o,返回被替换的元素(原来的)。
Object remove(int index) 移除第index个元素,返回移除的元素。
实现List的常用类
实现List接口的常用类有:LinkedList,ArrayList,Vector,Stack
LinkedList类
LinkedList实现了List接口,允许null元素。LinkedList是异步(Asynchronous)的。
构造器:
LinkedList() 空的集合
LinkedList(Collection c) 包含c集合所有元素的集合,c不可以为null,否则抛出异常。
方法:
element() 返回集合的头(第一个元素)
get(int index) 返回index索引的元素
getFirst() 返回第一个元素
getLast() 返回最后一个元素
indexOf(Object o) 同List
lastIndexOf(Object o) 同List
peek() 返回第一个元素,同element()
poll() 找到并删除头(第一个元素)
set(int index , E element) 同List
ArrayList类
ArrayList类允许所有元素,包括null。ArrayList是异步(Asynchronous)的。
三个构造方法:
ArrayList() 构造空的ArrayList对象,初始容量10.
ArrayList(int initialCapacity) 构造有初始容量的ArrayList集合
ArrayList(Collection c) 包含集合c中所有元素的ArrayList集合。
方法:
boolean add(Object o) 将元素o加到集合末尾
add(int index , Object o) 将o插入到index位置,并且该位置及后面的元素全部后移。
boolean addAll(Collection c) 将c集合所有元素,加到集合末尾
boolean addAll(int index,Collection c) 将集合c中所有元素插到index位置,被插队的后移。
void clear() 删除集合中所有元素
Object clone() 克隆集合,返回Object对象可以转换为集合。(深克隆,浅克隆???)
boolean contains(Object o) 集合是否包含元素o,包含返回true,否则返回false
void ensureCapacity(int minCapacity) 增加ArrayList对象容量。
get(int index) 返回指定索引的元素
int indexOf(Object o) 返回o第一次出现的位置,没有返回-1
int lastIndexOf(Object o) 返回o最后一次出现的位置,没有返回-1
boolean isEmpty() 判断集合是否为空,和size()==0一样
Object remove(int index) 删除指定位置的元素
boolean remove(Object o) 删除指定元素o,若存在多个重复的,只会删除一个,不会全部删除。
void removeRange(int fromIndex,int toIndex) 删除索引在from到to之间的所有元素,包括from,不包括to。
Object set(int index,Object o) 将index位置元素,替换为o,返回被替换的元素(原来的元素)。
int size() 集合大小(元素个数)
Object[] toArray() 返回包含所有元素的数组
void trimToSize() 将该ArrayList的容量调整为当前大小
Vector类
Vector类非常类似ArrayList,但是Vector是同步(Synchronous)的,由Vector创建的iterator,虽然和ArrayList创建的iterator是同一接口,但是因为Vector是同步的,当一个iterator被创建而且被使用时,另一个线程改变了这个Vector的状态,例如添加或删除了一些元素,这时调用iterator的方法时会抛出ConcurrentModificationException异常,需要捕获异常。
四个构造器:
Vector() 构造一个空的Vector对象,初始容量为10。(注:size()属性指的是元素个数,不是容量大小)
Vector(int initialCapacity) 构造初始容量的Vector对象。
Vector(int initialCapacity , int capacityIncrement) 构造初始容量和增量的Vector对象。增量是指当容量满了时,容量的增量。
Vector(Collection c) 构造以c集合中所有元素为初始数据的Vector对象。
方法:
addElement(Object o) 将元素o加到集合末尾。
void insertElementAt(Object o,int index) 将o元素插入到index位置,该位置和后面所有元素后移。
Stack类
Stack类继承自Vector类,实现一个后进先出的堆栈。Stack也是线程安全的。
Set接口
Set接口也是实现的Collection接口,但是Set是无序的,并且是没有重复元素的,若将重复的或已存在的元素(即两个元素equals相等)放入到Set中,没有任何操作(不会覆盖)。
证明:
Set s = new HashSet();
s.add("a");
String b = new String("a");
s.add(b);
Iterator i = s.iterator();
System.out.println(i.next()=="a");
输出:
true
新增加的new String("a")和"a"是equals相等的,但是将b加入后,输出结果仍为true,说明b没有将a覆盖,而是没有任何操作。
Set接口可以存入null。
Set接口常用方法:
(所有的Collection接口的方法都被继承)
boolean add(Object o) 将元素o加到集合中,若已存在,则无变化
boolean addAll(Collection c) 将c中所有元素加到集合中
void clear() 删除集合中所有元素
boolean contains(Object o) 判断集合中是否存在元素o,存在返回true,否则返回false
boolean containsAll(Collection c) 判断集合c中元素,是否在集合中全部存在,存在返回true,否则返回false。
boolean equals(Object o) 判断对象o是否与集合相等,相等返回true,否则返回false,相等的条件是:对象也是一个列表,两个列表有相同的大小,两个列表相同位置的元素都相等(3个条件需要都满足)。
boolean isEmpty() 判断集合是否为空
Iterator iterator() 返回集合的迭代器,用于对集合进行遍历。
boolean remove(Object o) 移除指定的元素,若不存在,集合无变化。
boolean removeAll(Collection c) 删除集合中,在参数集合c存在的全部元素。
boolean retainAll(Collection c) 与removeAll相反,除了c中存在的,其他全部删除。
int size() 返回集合元素个数
Object[] toArray() 将集合中元素以数组形式返回。
T[] toArray(T[] a) 将集合中所有元素,以数组形式返回,运行时类型与参数运行时类型相同。
HashSet类
虽然Set和List都实现了Collection接口,但是他们的实现方式是不一样的,List基本上是以Array为基础,但是Set则是在HashMap的基础上实现的。HashSet的存储方式是将HashMap中的Key作为Set中的对应存储项,看到HashSet的add方法便一目了然:
public boolean add(E e) {
return map.put(e, PRESENT)==null;}
这也是Set中为什么不能有重复项的原因,因为HashMap中key是不能重复的。
HashSet中可以添加null,但是由于不能重复,所以最多有一个null。HashSet不保证元素的顺序,即不但不会排序,连插入集合的顺序都不能保证,比如依次放入1,2.3,输出后可能为2,3,1。
HashSet构造方法:
HashSet() 构造空的HashSet对象,初始容量为16.
HashSet(int initialCapacity) 构造指定容量的对象
HashSet(Collection c) 以集合c中所有元素为基础数据的HashSet对象。
LinkedHashSet类
LinkedHashSet是HashSet的一个子类,是一个链表。
SortedSet类
SortedSet继承自Set接口,不但具有Set的全部功能,而且是一个Sorted类型的Set。不管插入的顺序是什么,集合都会有顺序的进行升序排列。
SortedSet常用方法:
Object first() 返回SortedSet中第一个元素。
Object last() 返回最后一个元素。
SortedSet headSet(Object toElement) 返回所有小于指定元素,但不包括指定元素的SortedSet。
SortedSet tailSet(Object fromElement) 返回所有大于指定元素,并且包括指定元素的SortedSet。
SortedSet subset(Object formElement , Object toElement) 返回从起始元素到指定元素中所有元素,但不包括结束元素的SortedSet集合。
TreeSet类
TreeSet类是SortedSet的子类,是有顺序的。TreeSet是SortedSet的唯一实现形式。
TreeSet构造方法:
TreeSet() 返回空的TreeSet对象。
TreeSet(Collection c) 以集合c中所有元素为初始内容的集合。
TreeSet(Comparator c) c为指定的比较器,返回具有指定比较器的空的TreeSet对象。
TreeSet(SortedSet s ) 返回以s集合中所有的元素为基础数据的TreeSet集合。
例如,创建TreeSet对象并遍历:
SortedSet ss = new TreeSet();
ss.add("1");
ss.add("12");
ss.add("50");
ss.add("31");
Iterator i = ss.iterator();
while(i.hasNext()){
System.out.println(i.next());
}
输出结果是升序排列的:
1
12
31
50
队列Queue
Queue接口与List、Set同一级别,都是继承了Collection接口。LinkedList实现了Queue接 口。Queue接口窄化了对LinkedList的方法的访问权限(即在方法中的参数类型如果是Queue时,就完全只能访问Queue接口所定义的方法 了,而不能直接访问 LinkedList的非Queue的方法),以使得只有恰当的方法才可以使用。BlockingQueue 继承了Queue接口。
Java提供的线程安全的Queue可以分为阻塞队列和非阻塞队列,其中阻塞队列的典型例子是BlockingQueue,非阻塞队列的典型例子是ConcurrentLinkedQueue,在实际应用中要根据实际需要选用阻塞队列或者非阻塞队列。
阻塞队列和非阻塞队列对比:
BlockingQueue,顾名思义,“阻塞队列”:可以提供阻塞功能的队列。
首先,BlockingQueue提供的常用方法:
可能报异常 返回布尔值 可能阻塞 设定等待时间
入队 add(e) offer(e) put(e) offer(e, timeout, unit)
出队 remove() poll() take() poll(timeout, unit)
查看 element() peek() 无 无
add(e) remove() element() 方法不会阻塞线程。当不满足约束条件时,会抛出IllegalStateException 异常。例如:当队列被元素填满后,再调用add(e),则会抛出异常。
offer(e) poll() peek() 方法即不会阻塞线程,也不会抛出异常。例如:当队列被元素填满后,再调用offer(e),则不会插入元素,函数返回false。
要想要实现阻塞功能,需要调用put(e) take() 方法。当不满足约束条件时,会阻塞线程。
ConcurrentLinkedQueue,它是一个无锁的并发线程安全的队列。
对比锁机制的实现,使用无锁机制的难点在于要充分考虑线程间的协调。简单的说就是多个线程对内部数据结构进行访问时,如果其中一个线程执行的中途因为一些原因出现故障,其他的线程能够检测并帮助完成剩下的操作。这就需要把对数据结构的操作过程精细的划分成多个状态或阶段,考虑每个阶段或状态多线程访问会出现的情况。
ConcurrentLinkedQueue有两个volatile的线程共享变量:head,tail。要保证这个队列的线程安全就是保证对这两个Node的引用的访问(更新,查看)的原子性和可见性,由于volatile本身能够保证可见性,所以就是对其修改的原子性要被保证。
队列详细内容:
队列是一种数据结构.它有两个基本操作:在队列尾部加人一个元素,和从队列头部移除一个元素就是说,队列以一种先进先出的方式管理数据。
常用方法:
add 增加一个元索 如果队列已满,则抛出一个IIIegaISlabEepeplian异常
remove 移除并返回队列头部的元素,如果队列为空,则抛出一个NoSuchElementException异常
element 返回队列头部的元素,如果队列为空,则抛出一个NoSuchElementException异常
offer 添加一个元素并返回true,如果队列已满,则返回false
poll 移除并返问队列头部的元素,如果队列为空,则返回null
peek 返回队列头部的元素,如果队列为空,则返回null
put 添加一个元素,如果队列满,则阻塞
take 移除并返回队列头部的元素,如果队列为空,则阻塞
remove、element、offer 、poll、peek 其实是属于Queue接口。
java.ulil.concurrent包提供了阻塞队列的4个变种:
LinkedBlockingQueue:
默认情况下是没有上限的,但是也可以选择指定其最大容量,它是基于链表的队列。此队列按 FIFO(先进先出)排序元素。
ArrayBlockingQueue:
ArrayBlockingQueue在构造时需要指定容量,并可以选择是否需要公平性,如果公平参数被设置true,等待时间最长的线程会优先得到处理(其实就是通过将ReentrantLock设置为true来 达到这种公平性的:即等待时间最长的线程会先操作)。通常,公平性会使你在性能上付出代价,只有在的确非常需要的时候再使用它。它是基于数组的阻塞循环队列,此队列按先进先出原则对元素进行排序。
PriorityBlockingQueue:
PriorityBlockingQueue是一个带优先级的队列,而不是先进先出队列。元素按优先级顺序被移除,该队列也没有上限。但是如果队列为空,那么取元素的操作take就会阻塞,所以它的检索操作take是受阻的。另外,往入该队列中的元 素要具有比较能力。
DelayQueue:
最后,DelayQueue(基于PriorityQueue来实现的)是一个存放Delayed 元素的无界阻塞队列,只有在延迟期满时才能从中提取元素。该队列的头部是延迟期满后保存时间最长的 Delayed 元素。如果延迟都还没有期满,则队列没有头部,并且poll将返回null。当一个元素的 getDelay(TimeUnit.NANOSECONDS) 方法返回一个小于或等于零的值时,则出现期满,poll就以移除这个元素了。此队列不允许使用 null 元素。
以上就是关于java集合的知识点整理,欢迎大家一起留言沟通~