Java之集合(一)接口及抽象类
转载请注明源出处: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之集合(一)接口及抽象类的更多相关文章
- Java集合-07Map接口及其抽象类
简介 前面把List基本记录完了,对于集合List,Map,Set,因为Set基于Map,故先记录Map. 这一篇主要记录Map接口及其抽象类(java version:1.8) 整体架构 参考上图, ...
- 1)Java学习笔记:接口和抽象类的异同
Java接口和抽象类很像,他们有哪些相同点和异同点呢,下面我们做一个小结 相同 ① 都不能被实例化,都位于继承树的顶端,用于被实现或者继承 ② 都可以包含抽象方法,实现接口或者继承抽象类的普通子类都必 ...
- 学JAVA第十八天,接口与抽象类进一步加深
昨天老师讲了建网站,还要交钱买东西的,所以就没写,今天讲了接口与抽象类进一步加深 上完今天的课后,我才知道一个接口可以有多个实现类,一个实现类可以同时接多个接口. 现在就用代码来解释吧!!! 举例用人 ...
- Java学习笔记之接口和抽象类
接口(interface)1.interface创建一个接口,implements实现接口 interface jiekou{} class lie implements jiekou{}2.接口可以 ...
- 【知了堂学习笔记】java 接口与抽象类
本次主角:抽象类 .接口. 对于皮皮潇这样一类的Java初学者来说,接口和抽象类如果不去花大量的精力与时间是很难弄清楚的,而我也是在最近这周的项目学习中感觉到了我对这两个概念不熟悉,所以导致对一些问题 ...
- C++虚函数virtual,纯虚函数pure virtual和Java抽象函数abstract,接口interface与抽象类abstract class的比较
由于C++和Java都是面向对象的编程语言,它们的多态性就分别靠虚函数和抽象函数来实现. C++的虚函数可以在子类中重写,调用是根据实际的对象来判别的,而不是通过指针类型(普通函数的调用是根据当前指针 ...
- Java之集合(七)Map
转载请注明源出处:http://www.cnblogs.com/lighten/p/7327216.html 1.前言 按照顺序,本章本是要对Set的相关类进行介绍及讲解的.但是对于其实现有所了解的都 ...
- Java接口和抽象类的区别
今天看到项目中,写了一个抽象类,里面有很多方法继承了这类,当调用这个接口时,采用的是这个抽象类去调方法的,当时一想,这个不就是我们说的Java的多态的特征: 继承:存在继承关系的子类和父类 重写:子类 ...
- [JAVA设计模式]第一部分:接口、抽象类、设计原则
声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...
随机推荐
- 44 The shopping psychology 购物心理
The shopping psychology 购物心理 ①People can be addicted to different things ---e. g.,alcohol, drugs, ce ...
- Django入门与实践-第24章:我的账户视图(完结)
http://127.0.0.1:8000/settings/account/ #好的,那么,这部分将是我们最后的一个视图.之后,我们将专心来改进现有功能. #accounts/views.py fr ...
- [GO]小技巧,如何实现一个链式操作
package main import "fmt" type Stu struct { Name string Age int } func (p *Stu) SetName(na ...
- python 求最大子序列
动态规划的本质,是对问题状态的定义和状态转移方程的定义.dynamic programming is a method for solving a complex problem by breaki ...
- Ubuntu在命令行开启远程桌面
在终端执行下列三个命令即可 gsettings set org.gnome.Vino enabled truegsettings set org.gnome.Vino prompt-enabled f ...
- String 简介
特性: 1.字符串的不可改变性 String s="a"+"b"+"c"; 创建了四个对象 在方法常量池中存储 a“,”b“,”c“, ...
- 建立多人协作git仓库/git 仓库权限控制(SSH)
转载文章请保留出处 http://blog.csdn.net/defeattroy/article/details/13775499 git仓库是多人协作使用的,可以基于很多种协议,例如http.g ...
- Feed back TFS 2017 RC upgrade status to product team in product group 2017.03.01
作为微软的MVP,有一个我最喜欢的好处,就是可以与产品组(产品研发部门)有零距离接触,可以最先拿到即将发版的产品,并且和产品组沟通,对产品中出现的问题实时反馈. 看到TFS产品组吸收了自己的建议和反馈 ...
- 关于C_Sharp集中处理异常
1.写在前面 “异常意味着什么?”,想必不用对此做多余的解释,我们有理由相信在任何情况下任何应用程序都有可能出现异常,若在程序中没有对异常进行处理,则操作系统会以粗暴的方式处理掉它(弹出错误提示框), ...
- ASP.NET开发常用简单实用的方法
ASP.NET开发简单实用的方法 一.打印和导出 打印和导出EXCEL在目前ASP.NET开发中可以说是必要的,有时候针对不同数据难易程度下,用有效快速的方法是解决办法的有效途径之一. 1.打印 后台 ...