转载请注明源出处:http://www.cnblogs.com/lighten/p/7278655.html

1.前言

  从本章开始介绍Java的集合类,这些类主要存在于java.util包下,该系列基于JDK8,类中所包含的JDK8的lambda表达式的相关内容不进行介绍,只关注集合本身的使用方法。

2.集合体系

  

  上图就是Java中的集合主要层次结构了,所有的集合都需要实现Iterable<T>接口,最上层的是通用的Collection接口定义,然后就是较为熟悉的三种结构:List、Queue和Set了。下面又根据不同的特性有了子类接口。右图就是相关的抽象实现了,所有具体的类都会对应继承这些抽象实现。Map不在本章讨论范围内,之后涉及到的时候会先讲解Map的实现。

3.接口定义和部分实现

3.1 Collection

  上图是JDK8中集合的接口定义,不关注JDK8的新特性,有如下接口:

  1.size():集合中元素的个数

  2.isEmpty():集合是否为空

  3.contain(Object):集合是否包含某个元素

  4.iterator():获取集合的迭代器

  5.toArray():返回集合中的元素数组

  6.toArray(T[]):将集合中的元素放入所给数组中,如果所给数组大于集合大小,补充null。如果数组小于集合大小,返回数组大小的集合元素(实际集合元素个数小于数组大小依旧补充null)。

  7.add(E):向集合中添加一个元素

  8.remove(Object):在集合中移除指定的元素

  9.containsAll(Collection<?>):集合是否包含指定集合的全部元素,有一个没有就返回false

  10.addAll(Collection<?>):将指定的集合中全部的元素添加到该集合中,返回值的含义并不是全部成功,而是集合的元素有所改变就是true.(做并集A∪B)

  11.removeAll(Collection<?>):将指定的集合中全部的元素都从该集合中移除,返回值的含义是移除操作造成该集合有所改变就是true。(A-A∩B)

  12.retainAll(Collection<?>):这个方法和removeAll相反,其含义是该集合只保留指定集合中的元素,移除其它元素,有改变就是true。(实际就是做交集,保留交集部分A∩B)

  上述方法就是每一个集合所必备的相关方法。AbstractCollection抽象类中,几乎实现了所有的接口方法,除了以下三个:size()、iterator()和add()方法,其它方法的实现都是基于这三个抽象方法的(add不是抽象方法,其直接抛出异常,需要子类覆盖,所以此处也视为抽象方法)。当然,实现的方法也许在子类中会被覆盖,不过也基本是实现完了可以实现的功能。

3.2 List

  List接口继承自Collection接口。除了Collection接口的方法外,还增加了以下与位置相关的方法:

  1.get(int):获取指定位置的元素

  2.set(int,E):替换指定位置的元素

  3.add(int,E):将元素插入指定位置

  4.remove(int):移除指定位置的元素

  5.indexOf(Object):返回指定元素第一次在list中出现的位置,没有就是-1

  6.lastIndexOf(Object):返回指定元素最后一次在list中出现的位置,没有就是-1

  7.listIterator():返回一个list类型的迭代器,比一般的迭代器提供了前移的方法

  8.listIterator(int):返回一个从指定位置开始的list的list类型迭代器。

  9.subList(int,int):返回一个子list,范围是[start,end)

  10.addAll(int, Collection):将一个集合中的元素从指定位置开始全部插入

  list接口的抽象类AbstractList也是对应的继承了AbstractCollection类,当然也需要实现list接口。对于AbstractCollection中实现的方法,AbstractList大体没有变化,除了add(E)和iterator()方法其有具体实现了。add(E)方法是通过add(int,E)方法实现的,其它与位置有关list接口定义的方法都没有实现,需要具体子类去覆盖实现。其它值得一提的方法有indexOf和lastIndexOf,clear()等方法,其实现都是通过listIterator()迭代器完成的,而不是一般的迭代器。而后重要的就是三个实现类了:Itr、ListItr和SubList。

  Itr这个普通的迭代器的内容很简单,就如上图。cursor是当前读取的元素下标,所以hasNext的判断就是其不等于list大小就是true。lastRet是记录上一个位置,原因是调用next的时候cursor会自增1,这个时候remove方法就得需要上一次的位置才能删除当前对象。expectedModCount是用来判断并发修改的,迭代器虽然允许边遍历边删除,但是并不允许并发遍历删除。了解了这个,其实现也就很好理解:

  ListItr的实现是继承了Itr类的,其就是增加了前移操作和set、add操作,操作也依旧容易,根据Itr的原理,只需要处理cursor和lastRet就可以了。

  set和add方法就是通过当前位置来调用list的相关方法完成。

  SubList是直接继承自AbstractList类的,其接受一个list,和起始,终止坐标。但是要注意的是,SubList持有的是传入的list的引用,对SubList进行修改操作都会影响原list的内容,其只是限定了一下操作边界而已,并不是真正意义上的一个新的拷贝list。并且多线程操作sublist是不允许的,按照代码来看,多线程操作不同的sublist,这些sublist持有同一个list也是不被允许的。

    @Test
public void test() {
List<Integer> list = new ArrayList<>();
for(int i = 0; i < 5; i++) {
list.add(i);
}
List<Integer> sub = list.subList(1, 3);
sub.set(0, 100);
System.out.println(Arrays.toString(list.toArray()));
}

测试多线程的情况:

    @Test
public void test2() throws InterruptedException {
int threadNum = 3;
int all = 10000;
List<Integer> list = new ArrayList<>();
for(int i = 0; i < all; i++) {
list.add(i);
}
int per = all / threadNum;
CountDownLatch latch = new CountDownLatch(threadNum);
ExecutorService service = Executors.newCachedThreadPool();
CyclicBarrier barrier = new CyclicBarrier(threadNum);
for(int i = 0; i < threadNum; i++) {
service.submit(new TestTask(list.subList(i*per, (i+1)*per), barrier, latch));
}
latch.await();
} class TestTask implements Runnable { private List<Integer> sub;
private CyclicBarrier barrier;
private CountDownLatch latch; public TestTask(List<Integer> sub, CyclicBarrier barrier, CountDownLatch latch) {
this.sub = sub;
this.barrier = barrier;
this.latch = latch;
} public TestTask(List<Integer> sub, CountDownLatch latch) {
this.sub = sub;
this.latch = latch;
} @Override
public void run() {
try {
if(barrier != null) {
barrier.await();
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
try {
System.out.println(Thread.currentThread().getName());
for(int i = 0; i < sub.size(); i++) {
sub.remove(i);
}
System.out.println(Thread.currentThread().getName()+" over!");
} catch(Throwable e) {
e.printStackTrace();
} finally {
latch.countDown();
}
} }

  这个测试实际上并不规范,第一个实际运行的时候没有模拟出并发,看允许还是一个个线程执行的,第二个是sublist并不是抽象父类中的sublist,ArrayList重写了这个sublist。但还是可以参考一下。

3.3 Queue

  Queue队列结构也是继承了Collection接口,上图是其独自定义的一些方法。

  1.add(E):添加一个元素入队列,队列有容量限制时,超过容量抛出异常

  2.offer(E):添加一个元素入队列,在队列有容量限制的时候比add方法更好,不会抛出异常

  3.remove():检索并移除队列头,与poll不一样的地方在于如果队列为空,抛出异常

  4.poll():检索并移除队列头,队列为空返回NULL

  5.element():检索不移除,返回队列头,队列为空抛出异常

  6.peek():检索不移除,返回队列头,队列为空返回NULL

  AbstractQueue继承了AbstractCollection类,并实现Queue接口。其实现了add、remove和element方法,做法是借助未实现的offer、poll和peek方法,没有什么可说的地方。

3.4 Set

  Set接口继承了Collection,并没有添加新的方法。其抽象实现类AbstractSet也没有做什么改变,AbstractCollection未实现的add,size,iterator均没有实现,只是重写了一下removeAll方法,减少了一下迭代次数而已。

Java之集合(一)接口及抽象类的更多相关文章

  1. Java集合-07Map接口及其抽象类

    简介 前面把List基本记录完了,对于集合List,Map,Set,因为Set基于Map,故先记录Map. 这一篇主要记录Map接口及其抽象类(java version:1.8) 整体架构 参考上图, ...

  2. 1)Java学习笔记:接口和抽象类的异同

    Java接口和抽象类很像,他们有哪些相同点和异同点呢,下面我们做一个小结 相同 ① 都不能被实例化,都位于继承树的顶端,用于被实现或者继承 ② 都可以包含抽象方法,实现接口或者继承抽象类的普通子类都必 ...

  3. 学JAVA第十八天,接口与抽象类进一步加深

    昨天老师讲了建网站,还要交钱买东西的,所以就没写,今天讲了接口与抽象类进一步加深 上完今天的课后,我才知道一个接口可以有多个实现类,一个实现类可以同时接多个接口. 现在就用代码来解释吧!!! 举例用人 ...

  4. Java学习笔记之接口和抽象类

    接口(interface)1.interface创建一个接口,implements实现接口 interface jiekou{} class lie implements jiekou{}2.接口可以 ...

  5. 【知了堂学习笔记】java 接口与抽象类

    本次主角:抽象类 .接口. 对于皮皮潇这样一类的Java初学者来说,接口和抽象类如果不去花大量的精力与时间是很难弄清楚的,而我也是在最近这周的项目学习中感觉到了我对这两个概念不熟悉,所以导致对一些问题 ...

  6. C++虚函数virtual,纯虚函数pure virtual和Java抽象函数abstract,接口interface与抽象类abstract class的比较

    由于C++和Java都是面向对象的编程语言,它们的多态性就分别靠虚函数和抽象函数来实现. C++的虚函数可以在子类中重写,调用是根据实际的对象来判别的,而不是通过指针类型(普通函数的调用是根据当前指针 ...

  7. Java之集合(七)Map

    转载请注明源出处:http://www.cnblogs.com/lighten/p/7327216.html 1.前言 按照顺序,本章本是要对Set的相关类进行介绍及讲解的.但是对于其实现有所了解的都 ...

  8. Java接口和抽象类的区别

    今天看到项目中,写了一个抽象类,里面有很多方法继承了这类,当调用这个接口时,采用的是这个抽象类去调方法的,当时一想,这个不就是我们说的Java的多态的特征: 继承:存在继承关系的子类和父类 重写:子类 ...

  9. [JAVA设计模式]第一部分:接口、抽象类、设计原则

    声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...

随机推荐

  1. Struts has detected an unhandled exception

    这个问题是struts和jsp页面的配置之间产生了问题,就是struts里边的名字和jsp里用的名字不是同一个名字,所以无法识别,所以检查一下里边的命名.

  2. VHDL的库

    STD_LOGIC_ARITH 扩展了UNSIGNED.SIGNED.SMALL_INT(短整型)三个数据类型,并定义了相关的算术运算和转换函数. --======================== ...

  3. Codeforces735D Taxes 2016-12-13 12:14 56人阅读 评论(0) 收藏

    D. Taxes time limit per test 2 seconds memory limit per test 256 megabytes input standard input outp ...

  4. OpenGl 中的基本数据类型

    OpenGl 中的基本数据类型 为了便于 OpenGL在各种平台上移植,OpenGL定义了自己的数据类型. 如果你愿意也可用这些数据类型对应的标准C的数据类型来替代.如OpenGL也定义 GLvoid ...

  5. STL中的Vector相关用法

    STL中的Vector相关用法 标准库vector类型使用需要的头文件:#include <vector>. vector 是一个类模板,不是一种数据类型,vector<int> ...

  6. 绩效沟通的best原则

    绩效沟通-BEST原则 BEST原则指在进行绩效/IDP面谈的时候按照以下步骤进行: 案例:小赵经常在制作标书时候犯错误 Behavior description 描述行为 小赵,8月6日,你制作的标 ...

  7. hdu 4981

    中位数是否大于平均数 水题 #include <cstdio> #include <cstdlib> #include <cmath> #include <c ...

  8. zabbix-server启动报错解决

    启动zabbix-server有如下报错: 29171:20180714:084911.367 cannot start alert manager service: Cannot bind sock ...

  9. Jenkins中执行docker命令报错

    Cannot connect to the Docker daemon. Is the docker daemon running on this host?   在配置Jenkins从Gitlab自 ...

  10. 3D空间中射线与三角形的交叉检测算法【转】

    引言 射线Ray,在3D图形学中有很多重要的应用.比如,pick操作就是使用射线Ray来实现的,还有诸如子弹射线的碰撞检测等等都可以使用射线Ray来完成.所以,在本次博客中,将会简单的像大家介绍下,如 ...