转载请注明源出处: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. python中的list和array的不同之处 及转换

    python中的list和array的不同之处list是列表,可以通过索引查找数值,但是不能对整个列表进行数值运算 In [96]: b=[1,2] In [97]: b[1]Out[97]: 2In ...

  2. 2017 pycharm 激活码

    BIG3CLIK6F-eyJsaWNlbnNlSWQiOiJCSUczQ0xJSzZGIiwibGljZW5zZWVOYW1lIjoibGFuIHl1IiwiYXNzaWduZWVOYW1lIjoiI ...

  3. (转) MVC身份验证及权限管理-2

    转自:http://www.cnblogs.com/ldp615/archive/2010/10/27/asp-net-mvc-forms-authentication-roles-authoriza ...

  4. 数据分析工具R和RStudio入门介绍

    https://www.cnblogs.com/yjd_hycf_space/p/6672995.html Python&R语言-python和r相遇:https://www.cnblogs. ...

  5. About DNS

    FQDN -- Fully Qualified Domain Name TTL -- Time To Live TLD -- Top Level Domain gTLD -- Generic Top ...

  6. struts2和JSON的数据交互

    一.实验环境 1.struts2基本包 2.json-plugin 在struts2的lib下可以找到. 3.web.xml 加入struts2 <filter> <filter-n ...

  7. MFC中和定时器使用

    在MFC中和定时器相关的有三个函数: 1.设置定时器(定义一个定时器的属性):         SetTimer( UINT nIDEvent, UINT nElapse, void (CALLBAC ...

  8. crosss compile VLC with OpenMAX on ARM board(RockChip RK3399),in order to use Hard Acceleration when decode video

    reference:http://www.x90x90x90.com/en/raspberry-pi-3-howto-compile-vlc-with-hardware-acceleration/ 1 ...

  9. hdu 4950 打怪

    http://acm.hdu.edu.cn/showproblem.php?pid=4950 给定怪兽血量h,你攻击力a,怪物回血力b,你攻击k次要休息一次,问能否杀死怪兽 特判一次打死怪兽的情况和第 ...

  10. 用 PHP 编写 http 服务器

    概述 众所周知,我们一般使用 PHP 开发Web程序时需要使用到比如Apache或Nginx等Web服务器来支持,那么有没有办法直接使用PHP开发HTTP服务器,答案当然是可以的,最近看了一遍Work ...