java中的集合类:
集合类存放的都是对象的引用,而非对象本身,出于表达上的便利,我们称集合中的对象就是指集合中对象的引用(reference)。
集合类型主要有3种:set(集)、list(列表)和map(映射)。
Java API中所用的集合类,都是实现了Collection接口,他的一个类继承结构如下:
Collection<--List<--Vector
Collection<--List<--ArrayList
Collection<--List<--LinkedList
Collection<--Set<--HashSet
Collection<--Set<--HashSet<--LinkedHashSet
Collection<--Set<--SortedSet<--TreeSet
具体的结构如下图:
其中实线边框为实现类如:ArrayList,LinkedList,HashSet,HashMap等;
折线边框为抽象类如:AbstractCollection,AbstractList,AbstractSet,AbstractMap等;
点线边框为接口如:Iterator,LinkIterator,List,Set,Map等。
集合类中的常用方法:
add(E e):将指定对象添加到该集合中;
remove(Object o):将指定对象从该集合中移除;
isEmpty():返回Boolean值,用于判断当前集合是否为空;
Iterator():返回在此集合的元素上进行迭代的迭代器,用于遍历集合中的对象;
size():返回int值,获取该集合中的元素个数;
可以发现所有的集合类都实现了Iterator接口:
在Java中Iterator为一个接口,它只提供了迭代了基本规则,在JDK中他是这样定义的:对 collection 进行迭代的迭代器。
迭代器取代了 Java Collections Framework 中的 Enumeration。迭代器与枚举有两点不同:
1、迭代器允许调用者利用定义良好的语义在迭代期间从迭代器所指向的 collection 移除元素。
2、方法名称得到了改进。
接口中方法的定义:
public interface Iterator {
boolean hasNext();
Object next();
void remove();
}
Object next():返回迭代器刚越过的元素的引用,返回值是Object,需要强制转换成自己需要的类型
boolean hasNext():判断容器内是否还有可供访问的元素
void remove():删除迭代器刚越过的元素
List接口:
有序的 collection,顺序就是对象插入的顺序(也称为序列)。此接口的用户可以对列表中每个元素的插入位置进行精确地控制。用户可以根据元素的整数索引(在列表中的位置)访问元素,并搜索列表中的元素。
List接口中除了Collection接口中的方法外还定义了两个重要的方法:
get(int index):获取指定索引位置的元素;
set(int index,Object o):将集合中指定索引位置的对象修改为指定对象;
与 Set接口不同,列表通常允许重复的元素。更确切地讲,列表通常允许满足 e1.equals(e2) 的元素对 e1 和 e2,并且如果列表本身允许 null 元素的话,通常它们允许多个 null 元素。
列表(像 Java 数组一样)是基于 0 的。
除了具有Collection接口必备的iterator()方法外,List还提供一个listIterator()方法,返回一个 ListIterator接口,和标准的Iterator接口相比,ListIterator在Iterator基础上添加了add,previous和hasPrevious方法;
实现List接口的常用类有LinkedList,ArrayList,Vector和Stack。
在使用List集合时通常声明为List类型,可通过不同的实现类来实例化集合;
LinkedList:
采用链表结构保存对象。这种结构的有点是便于想集合中插入和删除对象,对于随机访问集合中的对象效率比较低;
ArrayList:
实现了可变数组,允许保存所有的元素,包括null,并可以根据索引位置对集合进行快速的随机访问;缺点是想指定索引位置插入或删除对象速度比较慢;
以下是对ArrayList和LinkedList相关操作的实验:
在已有大量数据的ArrayList和LinkedList中批量插入数据:
ArrayList:
public class AboutArrayList {
public static void main(String[] args){
List<String> aList = new ArrayList<String>();
Long startTime = new Date().getTime();
for(int i = 0;i<100000;i++){
aList.add(i,null);
}
Long endTime = new Date().getTime();
System.out.println("ArrayList addTime:"+(endTime-startTime));
System.out.println("在已有大量数据的List中插入数据:");
startTime = new Date().getTime();
for(int i = 0;i<20000;i++){
aList.add(i,null);
}
endTime = new Date().getTime();
System.out.println("ArrayList addTime:"+(endTime-startTime));
System.out.println("随机查找效率:");
startTime = new Date().getTime();
for(int i =0;i<100;i++){
String str = aList.get(100000+i);
}
endTime = new Date().getTime();
System.out.println("LinkedList searchTime:"+(endTime-startTime));
}
}
在List的末尾插入数据:
ArrayList addTime:8
在已有大量数据的List中插入数据:
ArrayList addTime:679
随机查找效率:
LinkedList searchTime:0
LinkedList:
public class LinkedListAndArrayList {
public static void main(String[] args){
List<String> lList = new LinkedList<String>();
System.out.println("在List的末尾插入数据:");
Long startTime = new Date().getTime();
for(int j = 0;j<200000;j++){
lList.add(j,null);
}
Long endTime = new Date().getTime();
System.out.println("LinkedList addTime:"+(endTime-startTime));
System.out.println("在已有大量数据的List中插入数据:");
startTime = new Date().getTime();
for(int j = 0;j<20000;j++){
lList.add(j,null);
}
endTime = new Date().getTime();
System.out.println("LinkedList addTime:"+(endTime-startTime));
System.out.println("随机查找效率:");
startTime = new Date().getTime();
for(int i =0;i<100;i++){
String str = lList.get(100000+i);
}
endTime = new Date().getTime();
System.out.println("LinkedList searchTime:"+(endTime-startTime));
}
}
在List的末尾插入数据:
LinkedList addTime:21
在已有大量数据的List中插入数据:
LinkedList addTime:339
随机查找效率:
LinkedList searchTime:40
从结果中就可以看到他们的效率具体耗时应根据机器性能而定;
如果是在list的末尾插入数据结果相反ArrayList的效率要高于LinkedList;
Set接口:
Set集合中的对象不按特定的方式排序,只是简单的把对象加入集合中,但是Set集合中不能包含重复的对象,因此必须小心操作可变对象,如果一个可变对象改变了自身的状态导致了Object.equals(Object)=true;会出现一些问题。
Set接口中常用的实现类有HashSet和TreeSet;
HashSet:实现了Set接口由哈希表支持。他不保证Set迭代的顺序,特别不保证该顺序的不变性;允许使用null;
TreeSet:不仅实现了Set接口还实现了SortedSet接口,因此TreeSet类实现的Set集合在遍历时集合按照自然顺序递增排序,也可以按照指定比较器递增排序;
Map接口:
Map集合没有继承Collection接口,其提供的是key指向value的映射。
Map中不能包含相同的key,没过key只能映射一个value,key还决定了存储对象在映射中存储位置,但是不是由key本身决定的,而是通过散列技术实现的。
常用方法:
put(K key,V value):向集合中添加指定的key与value值的映射关系;
get(Object key):如果存在指定的key对象,则返回指定对象的value值否则返回null;
keySet():返回该集合中所有的key对象形成的Set集合;
values():返回该Map中所有的value值形成的集合;
Map接口的常用实现类有HashMap和TreeMap;
一般使用HashMap类实现Map接口,只在希望Map中对象有一定顺序的时候使用TreeMap实现;
HashMap:基于哈希表的Map接口的实现,允许使用null值和null键,但必须保证键的唯一性。此类不保证映射顺序;
TreeMap:不仅实现了Map接口还实现了SortedMap接口,因此集合中的映射关系具有一定的顺序,但是在添加,删除和定位映射关系是效率要低于HashMap;不允许键值对象为null;
可以通过HashMap类创建Map集合,当需要顺序输出时再创建一个完成相同的映射的TreeMap实例;