首页 >  IT技术问题 > Java技术问题 > 

Java五个最常用的集合类之间的区别和联系

Java五个最常用的集合类之间的区别和联系

作者:eld 来源:华育国际 时间:2015-07-22 访问次数:3840
如将自定义类用hashSet来添加对象,一定要覆盖hashcode()和equals(),覆盖的原则是保证当两个对象hashcode返回相同的整数,而且equals()返回值为True。

    1.ArrayList: 元素单个,效率高,多用于查询
    2.Vector:    元素单个,线程安全,多用于查询
    3.LinkedList:元素单个,多用于插入和删除
    4.HashMap:   元素成对,元素可为空
    5.HashTable: 元素成对,线程安全,元素不可为空
ArrayList
    底层是Object数组,所以ArrayList具有数组的查询速度快的优点以及增删速度慢的缺点。
    而在LinkedList的底层是一种双向循环链表。在此链表上每一个数据节点都由三部分组成:前指针(指向前面的节点的位置),数据,后指针(指向后面的节点的位置)。最后一个节点的后指针指向第一个节点的前指针,形成一个循环。
    双向循环链表的查询效率低但是增删效率高。
    ArrayList和LinkedList在用法上没有区别,但是在功能上还是有区别的。
LinkedList
    经常用在增删操作较多而查询操作很少的情况下:队列和堆栈。
    队列:先进先出的数据结构。
    栈:后进先出的数据结构。
    注意:使用栈的时候一定不能提供方法让不是最后一个元素的元素获得出栈的机会。
Vector
    与ArrayList相似,区别是Vector是重量级的组件,使用使消耗的资源比较多。
    结论:在考虑并发的情况下用Vector(保证线程的安全)。
    在不考虑并发的情况下用ArrayList(不能保证线程的安全)。
面试经验(知识点):
    java.util.stack(stack即为堆栈)的父类为Vector。可是stack的父类是最不应该为Vector的。因为Vector的底层是数组,且Vector有get方法(意味着它可能访问到并不属于最后一个位置元素的其他元素,很不安全)。
    对于堆栈和队列只能用push类和get类。
    Stack类以后不要轻易使用。
    实现栈一定要用LinkedList。
    (在JAVA1.5中,collection有queue来实现队列。)
Set-HashSet实现类:
    遍历一个Set的方法只有一个:迭代器(interator)。
    HashSet中元素是无序的(这个无序指的是数据的添加顺序和后来的排列顺序不同),而且元素不可重复。
    在Object中除了有finalize(),toString(),equals(),还有hashCode()。
    HashSet底层用的也是数组。
    当向数组中利用add(Object o)添加对象的时候,系统先找对象的hashCode:
    int hc=o.hashCode(); 返回的hashCode为整数值。
    Int I=hc%n;(n为数组的长度),取得余数后,利用余数向数组中相应的位置添加数据,以n为6为例,如果I=0则放在数组a[0]位置,如果I=1,则放在数组a[1]位置。如果equals()返回的值为true,则说明数据重复。如果equals()返回的值为false,则再找其他的位置进行比较。这样的机制就导致两个相同的对象有可能重复地添加到数组中,因为他们的hashCode不同。
    如果我们能够使两个相同的对象具有相同hashcode,才能在equals()返回为真。
    在实例中,定义student对象时覆盖它的hashcode。
    因为String类是自动覆盖的,所以当比较String类的对象的时候,就不会出现有两个相同的string对象的情况。
    现在,在大部分的JDK中,都已经要求覆盖了hashCode。

结论:
    如将自定义类用hashSet来添加对象,一定要覆盖hashcode()和equals(),覆盖的原则是保证当两个对象hashcode返回相同的整数,而且equals()返回值为True。
    如果偷懒,没有设定equals(),就会造成返回hashCode虽然结果相同,但在程序执行的过程中会多次地调用equals(),从而影响程序执行的效率。
    我们要保证相同对象的返回的hashCode一定相同,也要保证不相同的对象的hashCode尽可能不同(因为数组的边界性,hashCode还是可能相同的)。

例子:
    public int hashCode(){
    return name.hashcode()+age;
    }
    这个例子保证了相同姓名和年龄的记录返回的hashCode是相同的。

使用hashSet的优点:
    hashSet的底层是数组,其查询效率非常高。而且在增加和删除的时候由于运用的hashCode的比较开确定添加元素的位置,所以不存在元素的偏移,所以效率也非常高。因为hashSet查询和删除和增加元素的效率都非常高。
    但是hashSet增删的高效率是通过花费大量的空间换来的:因为空间越大,取余数相同的情况就越小。HashSet这种算法会建立许多无用的空间。
    使用hashSet类时要注意,如果发生冲突,就会出现遍历整个数组的情况,这样就使得效率非常的低。