java集合类是Java程序员经常使用的工具类。它里面的实现方式其实涵盖了很多的数据结果,比如:队列、栈。其中Java集合大致可以分为Set、List、Map三中体系。先主要从三个容器的使用、实现机制、使用场景做下分析总结。总结性概括:Set体系是无序的、不可重复的集合。List代表无序、可以重复。Map代表键值对。还有Queue体系结构。集合类的框架图如下:特性不同主要来源于实现的不一致性:
Set:set里面的元素是否相等的判断是通过 equal()方法进行。
public class SetTest {
public static void main(String[] args) {
Set set = new HashSet();
set.add(new String("book1"));
set.add(new String("book1")); //q,则两个对象,也是只插入一个数据
System.out.println(set); //[book1]
Set s = Collections.synchronizedSet(set) ;
}
}
HashSet类:不能保证元素的排列顺序,且不是同步的需要使用工具保证同步,值可以是null;
Set s = Collections.synchronizedSet(set) ;
HashSet判断两个元素相等的标准是通过equal()与HashCode()两个方法同时满足。
若equal通过,则HashCode不通过,则一样是两个不同的元素。放在不同的位置。hashCode是存放位置的值索引。
注意,如果需要重写equal的,也需要重写hashcode,使两者的步骤保持一致。如果hashCode相等,equal不等,则会放在同一个桶里,用链表存储。影响查询的性能。
LinkedHashSet类:保持插入的顺序
TreeSet类:
<pre name="code" class="java">public class TreeSetTest {
public static void main(String[] args) {
TreeSet set = new TreeSet();
set.add(1);
set.add(3);
set.add(2);
set.add(4);
System.out.println(set);
System.out.println(set.first());
System.out.println(set.headSet(2));//比2小的元素
System.out.println(set.tailSet(3)); //>=3的元素
System.out.println(set.subSet(2, 3));// 2<=X <3
}
}
TreeSet函数是compareTo(Object obj)进行比较的,所以如果要使用TreeSet进行对象的比较,对象需要实现Comparable接口,否则会抛异常
TreeSet treeSet = new TreeSet();
treeSet.add(new TreeSetTest());
treeSet.add(new TreeSetTest()); //抛异常
最好 不要对 HashSet 或者TreeSet集合引入可变对象,因为这样子,如果中间参数改变,则会影响treeSet的索引。
EnumSet类:专门为枚举类型而设计的一个集合类。
enum Eason{
Spring,Summer,Autom,Winter
}
public class EnumSetTest {
public static void main(String[] args){
EnumSet enumSet = EnumSet.allOf(Eason.class); //创建的集合包含全部的Eason
// enumSet.add("test"); //抛异常,不是枚举Eason类型
// enumSet.add(Eason.Winter); //不会重复加进去
System.out.println(enumSet);
EnumSet nullEnumSet = EnumSet.noneOf(Eason.class); //创建了个空集合
System.out.println(nullEnumSet);
EnumSet enumSet3 = EnumSet.of(Eason.Autom, Eason.Winter); //[Autom, Winter]
System.out.println(enumSet3);
EnumSet enumSet4 = EnumSet.range(Eason.Summer,Eason.Winter); //[Summer, Autom, Winter]
System.out.println(enumSet4);
}
}
各Set实现类的性能分析:都是非线性安全的,需要靠工具来维护:
SortedSet sortedSet = Collections.synchronizedSortedSet(new TreeSet());
HashSet:添加、查询
LinkedHashSet:遍历较快
TreeSet:保持有序 ,需要维护一个红黑树
EnumSet:性能最快,但是只能保存枚举值
List:是一个有序的,可重复的集合。
判断两个元素是否相等,也是通过equals进行判断。List提供的是listIterator()方法,该方法返回的是一个ListIterator()对象,继承了Iterator接口,直接看代码看他有哪些方法:
Queue集合
模拟队列的数据结构。
add(object o); peek();//获取队列头部元素,但不删除此元素,如果此队列为空,则返回null;poll();//获取队列头部元素,并删除该元素
offer(object o);此方法与add的作用类似,但是这个比较适用于有容量的限制的。
PriorityQueue实现类
是一个比较标准的队列实现类。按元素的优先级进行排序的。如果要放入两种排序方式:
一个是自然排序:不允许插入null元素。需要对队列元素进行排序。要实现comparable接口,
一种是定制排序:
ArrayDeque实现类(双端队列):与ArrayList类似,底层都是实现一个动态的数组形式保存。
public class ArrayDequeTest {
public static void main(String[] args) {
ArrayDeque stack =new ArrayDeque();
stack.push("try1");
stack.push("try2");
stack.push("try3");
System.out.println(stack); // [try3, try2, try1]
System.out.println(stack.peek()); // try3
System.out.println(stack); // [try3, try2, try1]
System.out.println(stack.pop()); // try3
System.out.println(stack); // [try2, try1]
}
}
LinkedList是List接口的实现类,实现了Deque接口,可以当成一个双端队列来使用。是一个链表。
LinkedList 在随机访问的时候性能较差,但是插入与删除的 时候性能较好,只要改变一下指针地址的位置。
ArrayList与ArrayDeque的是以数组的形式存放的。
各个线性表的性能分析:
Java提供的List是一个线性表接口,而ArrayList、LinkedList又是线性表的典型实现。Deque代表了队列,双端队列,既可以作为队列使用,也可以作为栈使用。
性能比较:
public class PerformanceTest {
public static void main(String args[]){
String[] str1=new String[900000];
for (int i=0;i<90000;i++){
str1[i]=String.valueOf(i);
}
ArrayList al = new ArrayList();
for (int i=0;i<90000;i++){
al.add(str1[i]);
}
LinkedList l1 =new LinkedList();
for (int i=0;i<90000;i++){
l1.add(str1[i]);
}
long start=System.currentTimeMillis();
for (Iterator it =al.iterator();it.hasNext();){
it.next();
}
System.out.println(System.currentTimeMillis()-start);
start=System.currentTimeMillis();
for (Iterator it =l1.iterator();it.hasNext();){
it.next();
}
System.out.println(System.currentTimeMillis()-start);
}
}
比较会发现,ArrayList 与LinkList在时间上略大。
- 需遍历List集合元素时,可采用迭代器来遍历全部元素。ArrayList与Vector集合,适用随机访问。
- 经常的要使用插入与删除操作时,使用LinkList。因为ArrayList与Vector是数组分配,性能开销较大。
- 如果考虑到List被多个线程访问不安全,则可以考虑将Collections集合包装秤线程安全的集合。
参考资料:
《疯狂Java讲义》