1.收集
Java设计了收集系列,提供了更复杂的方式保存对象。
收集又叫容器,它把多个元素放进一个单元里,形成一个对象。收集用于存储、读取、处理和交流聚集的数据。
Java的收集形成了收集框架的体系结构,包括接口、实现、算法三部分。
1.核心的收集接口有Collection、Set、List、Queue、Map等,标红的都是Collection的后继,所有的核心接口都是泛型的。
2.实现是指存储收集所用的数据对象,有通用目的实现、专用目的实现等。
3.收集的算法是一些静态方法,对收集执行有用的功能。常用的算法有排序、搅乱、常规数据处理、搜索、组合、寻找极值等。
1.1.Collection接口
这是收集系列的根,具有最大的通用性,允许重复元素存在,不要求元素排序等。通用目的的各种收集在实现时都用Collection作构造方法的参数,方便转换收集的类型。
Collection只有接口,没有实现。接口结构如下:
public interface Collection<E> extends Iterator<E>{
//基本操作
int size(); //返回收集的元素个数
boolean isEmpty(); //收集有无元素
boolean contains(Object element); //是否包含element元素
boolean add(E element); //加入element元素到收集
boolean remove(Object element); //删除element元素
Iterator<E> iterator(); //列举收集元素
//成批操作
boolean containsAll(Collection<?> c); //目标收集是否有指定收集c的所有元素
boolean addAll(Collection<?extends E> c); //加入指定收集元素到目标收集
boolean removeAll(Collection<?> c); //目标收集删除指定收集全部元素
boolean retainAll(Collection<?> c); //目标收集保留指定收集全部元素
void clear(); //清空收集
//数组操作
Object[] toArray(); //收集元素放进Object数组
<T> T[] toArray(T[] a); //收集元素放进T类型数组
}
1.1.1.遍历收集
把收集中的对象列举出来称为遍历收集。可以用for-each结构遍历,如:
for(Object o:collection)System.out.println(o);
1.1.2.Iterator接口
//Iterator接口的结构
public interface Iterator<E>{
boolean hasNext(); //收集若还有元素返回true
E next(); //取下一个元素
void remove(); //删除next()返回的最后一个元素
}
调用Collection接口的iterator()方法就可以得到Iterator对象。Iterator对象可以遍历收集,如果遍历收集时希望删除其元素,可以在调用next()后调用一次remove(),这是for-each结构遍历无法做到的。过滤任意Collection的多态代码如下:
Static void filter(Collection<?> c){
for(Iterator<?> it=c.iterator();it.hasNext;)
if(!cond(it.next()))
it.remove();
}
1.1.3.成批操作
成批操作是对整个Collection进行的,但这些操作也是用Collection接口的基本操作实现的。
1.1.4.数组操作
数组操作让Collection的内容转换到数组中。例如:Object[] a=c.toArray(); 将Collection对象c的内容导入Object数组中,数组长度与c的元素个数相同。
1.2.Set
Set是不能包含重复元素的Collection,它继承了Collection的方法。
Java平台有3种通用目的的Set实现:HashSet、TreeSet和LinkedHashSet。
1.HashSet用哈希表存放元素,实现性能最好,但不保证列举顺序。
2.TreeSet用红-黑树存放元素,按元素值排次序,比HashSet慢。
3.LinkedHashSet是链表实现的哈希表,按元素插入集合的顺序排次序,次序不混乱,但代价高一些,介于HashSet和TreeSet之间。由于HashSet速度快,除了要排序的情况下必须用TreeSet外,一般都用HashSet。
Set还有两个专用目的的实现,EnumSet和CopyOnWriteArraySet,暂不理会。
创建Set对象时总是用接口类Set做引用,如:
Set<String> s=new HashSet<String>();
或:Set<String> s=new HashSet<String>(32);
为HashSet设置32容量。其默认容量为16,若输入的容量不是2的幂,将会自动变成比这容量大的2的幂,例如设置15,实际容量为16。当元素个数大于容量,将会扩容。
补充:
若有一个已被创建的Set对象<String>a,可以:
Set<String> b=new Set<>(a); 创建一个元素与a相同的Set对象b。
1.2.1.Set接口示例
import java.util.*;
public class Test{
public static void main(String[] args) {
// TODO 自动生成的方法存根
String[] str={"Java技术及应用","qwq","awa"};
Set<String> s=new HashSet<>();
for(String str1:str)
s.add(str1);
System.out.println(s);
}
}
1.3.List
List是有序的Collection,又称为序列,基本上是按插入顺序排列的,可以包含重复元素。List接口继承了Collection的方法,删除操作总是删除列表中第一个出现的指定元素,加入操作总是加在列表的末尾。(有点像c的队列)
另外,List根据序列特性增加了一些方法,其结构如下:
public interface List<E> extends Collection<E>{
//按位置访问
E get(int index); //去指定下标的元素
E set(int index,E element); //设置指定下标的元素,返回原元素
boolean add(E element);
void add(int index,E element); //加入到指定位置
E remove(int index); //删除指定位置的元素,返回该元素
boolean addAll(int index,Collection<? extends E> c);
//搜索
int indexOf(Object o); //返回列表中第一次出现的指定元素的下标,或-1(无)
int lastIndexOf(Object o); //返回列表中最后一次出现的指定元素的下标,或-1
//列举
ListIterator<E> listIterator(); //从表头开始列举
ListIterator<E> listIterator(int index); //从指定位置开始列举
//范围视图,即显示一段范围的元素
List<E> subList(int from,in to);
}
Java平台有两种通用目的的List实现:ArrayList和LinkedList。前者提供固定时间的按位置访问,插入删除是线性时间,通常性能比较好;后者的插入删除是固定时间,在经常需要插入删除时性能稍好。
1.3.1.基本操作
创建ArrayList对象格式:List<Type> list=new ArrayList<Type>();
1.3.2.列举操作
List使用的ListIterator扩充了Collection接口的iterator,可以从两个方向遍历列表,可在列表期间修改列表,而且获得iterator的当前位置。 创建ListIterator对象的格式为:
List<Integer> list=new ArrayList<>();
ListIterator it=list.listIterator();
//也可以指定位置开始列举
//ListIterator it=list.lisIterator(2);
//从第三个元素开始列举
由于书上对ListIterator接口的方法讲解的太笼统,测试方法时感觉不太对,所以根据网上注解和具体运行修改了对ListIterator接口方法的注释,其结构如下:
public interface ListIterator<E> extends Iterator<E>{
boolean hasNext(); //是否存在下一个元素
boolean hasPrevious(); //前一个元素是否存在
E next(); //先取出当前指针指向的元素,再将指针向下移动
E previous(); //先将指针向前移动,再取出当前指针指向的元素
int nextIndex(); //测试:返回指针指向的下标
int previousIndex(); //测试:返回指针指向的前一个元素下标
void remove(); //删除next()或previous()返回的元素
void set(E e); //用指定元素设置next()或previous()返回的元素
void add(E e); //在当前指针指向的下标加入指定元素
//如果当前下标指向列表开头,调用previousIndex将返回-1
//如果当前下标指向列表的最后一个元素,调用nextIndex将返回list.size()
}
参考自:
ListIterator接口方法测试:
import java.util.*;
public class Test{
public static void main(String[] args) {
// TODO 自动生成的方法存根
List<String> list=new ArrayList<String>();
list.add("A");
list.add("B");
list.add("C");
System.out.println(list);
ListIterator<String> it=list.listIterator();
System.out.println(it.next()); //返回A,指针移动指向B
System.out.println(it.next()); //返回B,指针移动指向C
it.remove(); //删除next()返回的元素,故删除B
System.out.println(it.previous()); //指针移动指向A,返回A
System.out.println(it.nextIndex()); //指针现在指向A,返回下标0
System.out.println(it.previousIndex()); //指针现在指向A,返回-1
it.set("E"); //替换previous()返回的元素A
it.add("D"); //指针现在指向E,在下标0处添加元素D
System.out.println(list);
}
}
//输出结果
[A, B, C]
A
B
A
0
-1
[D, E, C]
还有一些需要注意的地方:remove()和set()操作都要跟随在next()或previous()方法后面,中间如果有add()操作,将会出错。
1.3.3.范围视图操作
范围视图即显示一段范围的元素。其相关方法subList(int from,int to)返回从from下标到to下标前的子列表,即包括from位置元素,不包括to位置元素。subList().clear()将清空子列表。
如果产生子列表后又在原列表加入或删除元素,那么子列表的语义就没定义。
1.3.4.List的数据结构应用
Collections类有许多算法适用于List,比如合并排序sort、随机搅乱shuffle、序列反向reverse、循环rotate、元素交换swap、全部替换replaceAll、填充fill、复制copy等等。
排序示例如下:
import java.util.*;
public class Test{
public static void main(String[] args) {
// TODO 自动生成的方法存根
Random r=new Random();
List<Integer> list=new ArrayList<>();
for(int i=0;i<10;i++)
list.add(r.nextInt(10));
System.out.println(list);
Collections.sort(list);
System.out.println(list);
Collections.reverse(list);
System.out.println(list);
}
}
1.4.Queue
Queue是保持元素重于处理元素的Collection,通常是按先进先出方式安排元素,在队尾插入元素,在队头删除元素;但优先队列是按值来安排的,不一定在队尾插入。
有些Queue实现时限制了所保持元素的数量,称为限界。
Queue接口增加了一些方法,如下:
public interface Queue<E> extends Collection<E>{
E element(); //返回队头元素,空队则抛出异常
boolean offer(E e); //在限界队列里加入元素
E peek(); //返回队头元素,空队返回null
E poll(); //删除并返回队头元素,空队则抛出异常
E remove(); //删除并返回队头元素,空队返回null
}
Queue接口有个子接口叫Deque接口,是支持在队列两端都可以插入和删除元素的线性收集(双端队列),Deque接口方法比Queue接口多。
1.4.1.Queue的实现
每种Queue实现必须说明它的安排性质:
LinkedList类实现了Queue接口,提供了先进先出队列的操作;
PriorityQueue类基于优先堆数据结构的优先队列,也实现了Queue接口;
BlockingQueue接口是并发Queue接口,定义了阻塞队列的方法,由SynchronousQueue类等几个并发队列实现。
创建Queue对象的格式是:Queue<Type> queue=new LinkedList<Type>();
创建PriorityQueue对象的格式是:Queue<Type> pq=new PriorityQueue<Type>();
LinkedList类和ArrayDeque类实现了Deque接口,这是可变长度的数组实现的双端队列,没有元素容量限制。
创建Deque对象的格式是:Deque<Type> pq=new ArrayDeque<Type>();
1.4.2.Queue的数据结构应用
import java.util.*;
//用优先队列实现堆排列
//将随机列表放入PriorityQueue构造方法中形成堆,
//然后逐个元素出队到列表,最后返回列表
class MyheapSort{
static<E> List<E> heapSort(Collection<E> c){ //形参也可以写成List<E> c
Queue<E> queue=new PriorityQueue<E>(c);
List<E> list=new ArrayList<E>();
while(!queue.isEmpty()) {
list.add(queue.remove());
}
return list;
}
}
//生成随机列表,运行heapSort方法
public class Test{
public static void main(String[] args) {
// TODO 自动生成的方法存根
Random r=new Random();
List<Integer> list=new ArrayList<>();
for(int i=0;i<10;i++)
list.add(r.nextInt(10));
System.out.println(list);
list=MyheapSort.heapSort(list);
System.out.println(list);
}
}
1.5.Map
Map是把键(Key)映射到值(Value)的对象。映射不能包含重复的键,一个键至少可以映射一个值,它是数学函数抽象的模型。
Map接口的结构是:
public interface Map<K,V>{
//基本操作
V put(K key,V value); //输入
V get(Object key); //返回键映射的值
V remove(Object key); //删除键
boolean containsKey(Object key); //是否包含key键
boolean containsValue(Object value);
//成批操作
void putAll(Map<? extends K,? extends V> m); //将m全部键和值加入目的Map
void clear;
//收集视图
public Set<K> keySet(); //取Map中键的集合,返回一个Set对象
public Collection<V> values(); //取Map中值的集合
public Set<Map.Entry<K,V>> entrySet; //取Map中键-值对的集合
//entrySet元素接口
public interface Entry{
K getKey();
V getValue();
V setValue(V value);
}
}
1.5.1.Map的实现
Java平台有三种通用目的的Map实现:HashMap、TreeMap和LinkedListMap,它们性能与HashSet、TreeSet和LinkedHashSet类似。HashMap速度最快,TreeMap可以排序,LinkedHashMap性能接近HashMap并保持插入顺序,但LinkedHashMap可以根据键遍历,它还有removeEldestEntry()方法删除旧映射。
1.5.2.基本操作
public class Test{
public static void main(String[] args) {
// TODO 自动生成的方法存根
Map<String,Integer> map=new HashMap<>();
map.put("Math",68);
map.put("Physics",82);
map.put("English", 90);
map.put("Chemistry", 75);
System.out.println(map);
System.out.println(map.get("Math"));
System.out.println(map.remove("Math"));
System.out.println(map);
System.out.println(map.containsKey("English"));
}
}
//输出
{English=90, Chemistry=75, Math=68, Physics=82}
68
68
{English=90, Chemistry=75, Physics=82}
true
1.如果用TreeMap构造Map对象,输出按字母顺序排列键。
2.如果用LinkedHashMap构造Map对象,输出按插入顺序排列键。
1.5.3.Map.Entry接口
Map有个嵌套的接口Map.Entry,可以实现按键-值对列举Map:
for(Map.Entry<KeyType,ValType> e:m.entrySet())
System.out.println(e.getKey()+" "+e.getValue());
m.entrySet()方法会返回一个Set对象,接口Entry是存储的元素的类型,(接口也是一种数据类型)
收集视图操作示例:
import java.util.*;
public class Test{
public static void main(String[] args) {
// TODO 自动生成的方法存根
Map<String,Integer> map=new HashMap<>();
Random r=new Random();
map.put("Math",r.nextInt(100));
map.put("Physics",r.nextInt(100));
map.put("English", r.nextInt(100));
map.put("Chemistry", r.nextInt(100));
System.out.println(map);
for(Map.Entry<String,Integer> e:map.entrySet())
System.out.println(e.getKey()+" "+e.getValue());
}
}
//输出
{English=26, Chemistry=18, Math=69, Physics=93}
English 26
Chemistry 18
Math 69
Physics 93
1.5.4.Map的数学应用
containsAll()、removeAll()、retainAll()等成批操作支持Map运算,例如:
//1.判断子集
if(m1.entrySet().containsAll(m2.entrySet())){
……
}
//2.判断两个Map有无共同的键集
//public Set<K> keySet();
System.out.println(m1.keySet().retainAll(m2.keySet()));
//3.删去共同键-值对
m1.entrySet().removeAll(m2.entrySet());
//4.实现多重Map,即一个键映射多个值,可以用List实例存放值
Map<String,List<String>> map=new HashMap<>();
1.6.SortedSet
SortedSet是按升序维护元素的Set,集合中的元素如果没有实现java.lang包的Comparable接口而无法比较,SortedSet就要提供java.util包的Comparable接口方法控制元素的次序。列举SortedSet元素时按其次序进行,转换成数组时元素仍是有序的。
SortedSet接口的核心结构是:
public interface SortedSet<E> extends Set<E>{
//范围视图
SortedSet<E> subSet(E fromElement,E toElement); //取[from,to)范围内的子集
SortedSet<E> headSet(E toElement); //取[最小值,to)范围内的子集
SortedSet<E> tailSet(E fromElement); //取[from,最大值]范围内的子集
//端点
E first(); //返回最小元素
E last(); //返回最大元素
//Comparator访问
Comparator<? super E> comparator();
}
1.6.1.SortedSet的实现
TreeSet类实现了SortedSet接口,它有4个构造方法:
1.TreeSet()
2.TreeSet(Collection<? extends E> c)
3.TreeSet(Comparable<? super E> comparable)
4.TreeSet(SortedSet<E> s)
暂时寄了