Java集合(一):Java集合概述
注:本文基于JDK 1.7
1 概述
Java提供了一个丰富的集合框架,这个集合框架包括了很多接口、虚拟类和实现类。
这些接口和类提供了丰富的功能。可以满足主要的聚合需求。
下图就是这个框架的总体结构图:
能够看见,这个框架很大,大到惊讶的地步。这个图的左面部分是接口,右面部分是类。中间的线代表了右面的类实现了左面的哪些接口。比方,AbstractList类实现了List接口。那么继承自AbstractList类的子类都实现了这个接口。还有,假设一个类实现了一个接口,那么这个类也实现了这个接口的全部父接口。
比方,TreeSet类实现了Deque接口,那么TreeSet类也实现了Queue接口、Collection接口和Iterable接口(接口Collection扩展了Iterable。这里没显示出来)。
图中红色的类表示抽象类,大部分抽象类都以Abstract开头,除了Dictionary。绿颜色的类表示遗留类,这些类在Java一開始的时候就已经存在了。
2 接口与实现分离
Java集合类库中将接口(interface)与实现(implementation)分离。这里以队列(queue)为例。
队列接口指出能够在队列的尾部加入元素,在队列的头部删除元素,而且能够查找队列中的元素个数。即队列中的元素依照先进先出的元素使用队列。
假设我们设计queue的接口,可能这样设计:
interface Queue<E>
{
void add(E element);
E remove();
int size();
}
这里给出了三个主要的方法。
这个接口没有给出队列应该是怎样实现的。通常。队列的实现方式有两种:一个是使用循环数组。一个是使用链表。
使用循环数组时须要指出对头head和队尾tail;使用链表时也须要给出头和尾:
class CircularArrayQueue<E> implements Queue<E>
{
CircularArrayQueue(int capacity){...}
public void add(E element){...}
public E remove(){...}
private E[] elements;
private int head;
private int tail;
} class LinkedListQueue<E> implements Queue<E>
{
LinkedListQueue(){...}
public void add(E element){...}
public E remove(){...}
public int size(){...}
private Link head;
private Link tail;
}
上面的仅仅是我们自己实现的简单的队列,Java类库中没有这两个类。
当须要使用队列时,能够使用LinkedList类。这个类实现了Queue接口。
当在程序中使用队列时,一旦构建了集合就不须要知道到底使用了哪种实现。
因此,仅仅有在构建集合对象时,使用详细的类才有意义。能够使用接口类型存放集合的引用:
Queue<Employee> employee=new CircularArrayQueue<>(100);
employee.add(new Employee("Harry"));
利用这样的方式,一旦改变了想法,能够轻松地使用还有一种不同的实现。仅仅须要对程序的一个地方做出改动,即调用构造器的地方。
假设认为LinkedListQueue是个更好的选择,就能够这样改动:
Queue<Employee> employee=new LinkedListQueue<>();
employee.add(new Employee("Harry"));
接口本身没有给出详细的实现方式。因此也不能给出哪种实现更符合实际应用。
这样,选择哪种实现方式就须要由程序猿选择。Java类库中实现了非常多的类,每一个类都有各自的特性以及适用场景,或许选择了某个实现方式在某个特性上更加优秀,但也可能在还有一个特性上付出了代价。
怎样平衡好各个性能的代价。须要类库使用者自己把握。
在上图中,我们能够发现非常多红色的以Abstract开头的类,这些类都是抽象类,这些类是为类库的实现者设计的,这些类中实现了一些主要的方法。假设想要实现自己的队列类,你会发现扩展AbstractQueue类比实现Queue接口更方便。
3 Java类库中的集合接口和迭代器接口
在Java类库中,集合类的基本接口是Collection接口。这个接口中有例如以下两个方法:
boolean add(E element);
Iterator<E> iterator();
当然,除了这两个方法外还有其他的方法,会在后面介绍。
add方法用于向集合中加入元素,假设加入元素确实改变了集合就返回true,假设集合没有发生变化就返回false。
iterator方法用于返回一个实现了Iterator接口的对象。
能够使用这个迭代器对象依次訪问集合中的元素。
以下来介绍一下Java类库中重要的迭代器。
Iterator迭代器接口有三个方法:
public interface Iterator<E>
{
E next();
boolean hasNext();
void remove();
}
通过重复调用next方法。能够逐个訪问集合中的每一个元素。
可是假设达到了集合的末尾,next方法将抛出一个NoSuchElementException异常。
因此,在调用next方法之前应该调用hasNext方法。假设迭代器对象还有多个供訪问的元素。这种方法就返回true。
因此,能够使用以下的方法訪问集合中的全部元素:
Collection<String> c=...;
Iterator<String> it=c.iterator();
while(it.hasNext())
{
String element=it.next();
do something with element
}
从Jave SE 5.0起。还能够使用for each循环訪问集合中的全部元素:
for(String element : c)
{
do something with element
}
编译器仅仅是将这个for each循环翻译为带有迭代器的循环。
for each循环能够与不论什么实现了Iterable接口的对象一起工作。这个接口仅仅包括一个方法:
public interface Iterable<E>
{
Iterator<E> iterator();
}
Collection接口扩展了Iterable接口。所以对于标准库中的不论什么集合都能够使用for each循环。
须要注意的是,元素被訪问的顺序取决于集合的类型。
假设对ArrayList进行迭代。迭代器将会从索引0開始。每迭代一次,索引值加1。然而,假设訪问HashSet中的元素。每一个元素将会依照某种随机的次序出现。尽管可以确定在迭代过程中可以遍历全部的元素。但却无法预知元素被訪问的次序。
Java集合类库中的迭代器与其他类库中的迭代器在概念上有着重要的差别。C++的迭代器是依据数组索引建模的。假设给定这样一个迭代器。就能够查看指定位置上的元素。就像知道数组索引i就能够查看数组元素a[i]一样。不须要查找元素,就能够将迭代器向前移动一个位置。
这与不须要运行查找操作就能够通过i++将数组索引向前移动一样。可是。Java迭代器不是这样操作的。
查找操作和位置变更是紧密相连的。查找一个元素的唯一方法是调用next。而在运行查找操作的同一时候,迭代器的位置随之向前移动。
即,能够将迭代器看做一个位置。这个位置在两个元素之间。
而next操作会改变这个位置。
但调用next时,迭代器就越过下一个元素,并返回刚刚越过的那个元素的引用。
Iterator接口的remove方法用于删除上次调用next方法返回时的元素。也就是说,remove操作和next操作具有依赖性,假设没有调用next方法而调用remove方法是非法的,会抛出一个IllegalStateException异常。
以下是删除集合中的第一个元素:
Iterator<String> it=c.iterator();
it.next();
it.remove();
假设删除两个相邻的元素,以下的方法是错误的:
it.remove();
it.remove();
必须先调用next方法越过待删除的元素:
it.remove();
it.next();
it.remove();
有一个不怎么恰当的比喻,能够将迭代器看做光标:
Collection<String> c=ArrayList<>();
c.add("a");
c.add("b");
c.add("c");
Iterator<String> it=c.iterator();
这时,迭代器的位置例如以下:
| a b c
当调用next方法,光标就会后移,然后返回刚才越过的元素:
it.next();
此时,迭代器的位置例如以下:
a | b c
并返回元素a。
假设要删除元素,删除的行为就像后退键(Backspace)一样,删除光标后面(以右为前)的元素:
it.remove();
此时,迭代器的位置例如以下:
| b c
和后退键不同的是,假设迭代器的后面即使还有元素,没有调用next方法也不能删除。
因为Collection接口和Iterator接口都是泛型接口,能够编写操作不论什么集合类型的有用方法。事实上,Collection接口中有非常多方法:
public interface java.util.Collection<E> extends java.lang.Iterable<E> {
public abstract int size();
public abstract boolean isEmpty();
public abstract boolean contains(java.lang.Object);
public abstract java.util.Iterator<E> iterator();
public abstract java.lang.Object[] toArray();
public abstract <T> T[] toArray(T[]);
public abstract boolean add(E);
public abstract boolean remove(java.lang.Object);
public abstract boolean containsAll(java.util.Collection<?>);
public abstract boolean addAll(java.util.Collection<? extends E>);
public abstract boolean removeAll(java.util.Collection<?>);
public boolean removeIf(java.util.function.Predicate<? super E>);
public abstract boolean retainAll(java.util.Collection<?>);
public abstract void clear();
public abstract boolean equals(java.lang.Object);
public abstract int hashCode();
public java.util.Spliterator<E> spliterator();
public java.util.stream.Stream<E> stream();
public java.util.stream.Stream<E> parallelStream();
}
有非常多的方法的含义都非常明白,这里不做过多的解释。
当然,假设实现Collection接口的每个类都要实现这些例行方法将是一件非常烦人的事。为了能够让实现者更easy地实现这个接口,Java类库提供了一个AbstractCollection类,在这个类里提供了一些例行方法。这样。一个详细的集合类就能够扩展AbstractCollection类而不须要实现全部的例行方法了。并能够覆盖里面的方法。
4 Java类库中的接口
下图给出了Java类库中的全部接口:
当中。Collection和Map是集合框架的两个主要接口。全部的集合类都实现了这两个接口中的一个。Iterator接口和ListIterator接口是迭代器接口。而ListIterator接口提供了更丰富的操作,这个接口会在List列表中介绍。
RandomAccess接口是一个标签接口。也就是说这个接口没有不论什么方法。可是能够用这个接口标注某个类,然后检查一个类是否支持随机訪问。
在随后的介绍中,会具体介绍这些接口的方法和使用。
5 Java类库中的类
以下是Java类库中的全部实现类:
当中红颜色的是抽象类。能够明显的分为两个部分,一个集合(Collection),一个映射(Map)。
这些是经常使用的类,再加上一些专用的类,比方:EnumSet、LinkedHashSet、EnumMap、LinkedHashMap、IdentityHashMap和WeakHashMap,一共14类,它们的特点例如以下:
集合类型 | 描写叙述 |
ArrayList | 一种能够动态增长和伸缩的索引序列 |
LinkedList | 一种能够在不论什么位置进行高效插入和删除操作的有序序列 |
ArrayDeque | 一种用循环数组实现的双端队列 |
HashSet | 一种没有反复元素的无序集合 |
TreeSet | 一种有序集 |
EnumSet | 一种包括枚举类型值的集 |
LinkedHashSet | 一种能够记住元素插入顺序的集 |
PriorityQueue | 一种同意高效删除最小元素的集合 |
HashMap | 一种存储键/值关联的数据结构 |
TreeMap | 一种键值有序排列的映射表 |
EnumMap | 一种键值属于枚举类型的映射表 |
LinkedHashMap | 一种能够记住键值项加入次序的映射表 |
WeakHashMap | 一种其值无用武之地后能够被垃圾回收器回收的映射表 |
IdentityHashMap | 一种使用==而不是equals比較键值的映射表 |
对于有序无序、元素可反复和元素不可反复。特点总结例如以下。注意,对于Map,考察的是键的值是否可反复:
6 很多其它
在后序的分析中,会给出这些详细类和集合的介绍:
Java集合(一):Java集合概述的更多相关文章
- Java基础知识强化之集合框架笔记16:List集合的特有功能概述和测试
1. List集合的特有功能概述: (1)添加功能: void add(int index, Object element):在指定位置添加元素 (2)获取功能: Object get(int ind ...
- Java笔记:Java集合概述和Set集合
本文主要是Java集合的概述和Set集合 1.Java集合概述 1)数组可以保存多个对象,但数组长度不可变,一旦在初始化数组时指定了数组长度,这个数组长度就是不可变的,如果需要保存数量变化的数据,数组 ...
- Java基础系列7——集合系列(1)框架概述
该系列博文会告诉你如何从入门到进阶,一步步地学习Java基础知识,并上手进行实战,接着了解每个Java知识点背后的实现原理,更完整地了解整个Java技术体系,形成自己的知识框架. 集合框架概述 Jav ...
- Java中的集合(上):概述、Collection集合、List集合及其子类
一.集合的体系结构 二.Collection集合 1.基本使用 如下代码 import java.util.ArrayList; import java.util.Collection; public ...
- java集合系列——java集合概述(一)
在JDK中集合是很重要的,学习java那么一定要好好的去了解一下集合的源码以及一些集合实现的思想! 一:集合的UML类图(网上下载的图片) Java集合工具包位置是java.util.* 二:集合工具 ...
- Java学习笔记之集合
集合(Collection)(掌握) (1)集合的由来? 我们学习的是Java -- 面向对象 -- 操作很多对象 -- 存储 -- 容器(数组和StringBuffer) -- 数组而数组的长度固定 ...
- Java基础---泛型、集合框架工具类:collections和Arrays
第一讲 泛型(Generic) 一.概述 1.JDK1.5版本以后出现的新特性.用于解决安全问题,是一个类型安全机制. 2.JDK1.5的集合类希望在定义集合时,明确表明你要向集合中装入那种类 ...
- java集合系列——List集合之ArrayList介绍(二)
一:List概述 List是 java.util包下面的类,从<a href="http://blog.csdn.net/u010648555/article/details/5604 ...
- java学习笔记—集合之Map集合
p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; text-align: center; font: 12.0px Times } p.p2 { margin: 0.0p ...
- [ Java学习基础 ] Java的对象容器 -- 集合
当你有很多书时,你会考虑买一个书柜,将你的书分门别类摆放进入.使用了书柜不仅仅使房间变得整洁,也便于以后使用书时方便查找.在计算机中管理对象亦是如此,当获得多个对象后,也需要一个容器将它们管理起来,这 ...
随机推荐
- MD5 algorithm in Objective C
How to calculate the MD5 in objective C ? md5 is available on the iPhone and can be added as an exte ...
- 在PythonAnyWhere上部署Django项目
http://www.jianshu.com/p/91047e3a4ee9 将项目放到git上,然后将pathonanywhere上的ssh传到git上,没有的话先创建,然后从git上把项目拷贝到pa ...
- 【性能优化】——前端性能优化之DOM
前言:本文参考学习自 RenChao Guan的博客,来源FSUX.ME,感谢原作者,本文的思维导图为自己整理 补充: 浏览器工作流程 避免重绘和回流的四种方式的具体实现
- 【温故知新】——Bootstrap响应式知识点复习
前言:本文是自己在学习课程中的课程笔记,这里用来温故知新的,并非本人原创. 开发工具 1.记事本,Editplus,... ... 2.Sublime,Dreamweaver 3.Webstorm = ...
- HTTP错误状态码定位与解决
实践总结 本次基于对500错误定位为例,给大家讲解整个分析过程与解决方法. 1.本次实践为HTTP错误状态码定位提供一个高效.精确的定位方式,不仅仅局限于500错误. 2.针对500错误本身,可以基于 ...
- cart算法
- vector(可变数组) 用于UDP通信
头文件: #include<vector.h> 然后,声明并初始化vctor数组. vector<char> str(len); 其中len可以是变量或者常量.(其实用常量就 ...
- Java使用笔记之对象比较
1.关于java对象的比较,经常会遇见比较某个两个对象的多个属性是否相等,可以通过重写对象equals方法来实现. 比如有两个User,如果姓名和年龄相等的话,我们就可以认为他们重复的数据.那么我们就 ...
- python中给程序加锁之fcntl模块的使用
python 中给文件加锁——fcntl模块import fcntl 打开一个文件##当前目录下test文件要先存在,如果不存在会报错.或者以写的方式打开f = open('./test')对该文件加 ...
- Atitit.ati dwr的原理and设计 attilax 总结 java php 版本号
Atitit.ati dwr的原理and设计 attilax 总结 java php 版本号 1. dwr的长处相对于ajax来说.. 1 2. DWR工作原理 1 3. Dwr的架构 2 4. 自己 ...