list,set,map总结

学习了集合,脑子里list,set,map之间的关系有混乱,在这里整理一下.有兴趣的朋友可以看下.

先看下 list,set,map各自的特点


List:
     索引数组:在内存空间上是连续的,计数也是连续的,总体就是有序的.下标是从0开始的,挨个递增的数组,可以通过数字下标找到相应的元素
   关联数组:在内存空间上是连续的,计数不是连续的,就是无序的.下标是字符串的数组,可以通过下标这个字符串去找相对应的元素
    ArrayList():
        List接口的大小可变数组的实现.实现了所有可选列表操作,并允许包括null在内的所有元素.
        每个ArrayList实例都有一个容器.该容器是指用来存储表元素的数组的大小.它总是至少等于列表的大小.随着向ArrayList中不断添加元素,其容量也自动增长.并未指定增长策略的细节,因为这不只是添加元素带来分摊固定时间开销那样简单
        ArrayList集合底层默认初始化容量是10,扩大容量后是原始容量的1.5倍;
        Vector:默认也是10,扩大容量是原来的2倍
        ArrayList是Vector的升级,所以Vector已经废弃
    针对数组代码的优化,尽量不要进行扩容操作,在建立集合的开始,就按照预估值指定初始化容量
    List集合的遍历方式:
        while-迭代器遍历
        for-迭代器遍历
        foreach-迭代遍历
        for-get遍历(只有List才可以,set,map都不可以)

    LinkedList:  

List 接口的链接列表实现。实现所有可选的列表操作,并且允许所有元素(包括 null)。除了实现 List 接口外,LinkedList 类还为在列表的开头及结尾 getremoveinsert 元素提供了统一的命名方法。这些操作允许将链接列表用作堆栈、队列双端队列

此类实现 Deque 接口,为 addpoll 提供先进先出队列操作,以及其他堆栈和双端队列操作。

所有操作都是按照双重链接列表的需要执行的。在列表中编索引的操作将从开头或结尾遍历列表(从靠近指定索引的一端)。

 

注意,此实现不是同步的。如果多个线程同时访问一个链接列表,而其中至少一个线程从结构上修改了该列表,则它必须 保持外部同步。(结构修改指添加或删除一个或多个元素的任何操作;仅设置元素的值不是结构修改。)这一般通过对自然封装该列表的对象进行同步操作来完成。如果不存在这样的对象,则应该使用 Collections.synchronizedList 方法来“包装”该列表。最好在创建时完成这一操作,以防止对列表进行意外的不同步访问,如下所示:

   List list = Collections.synchronizedList(new LinkedList(...));

注:LinkedList 参考于 JDK API 1.6.0 中文版



Set:
    HashSet:
    为什么会有hash(散列)?
        散列数据结构,但是java这里屏蔽了
        直接就用封装的形式把他封装到了 HashSet,HashMap,HashTable中,其中HashTable已经过时了
        hash算法:java中指的hashCode()函数及其重写
        目标:生成一个唯一的标识符
        根据对象的特点为每个对象生成一个唯一的hashCode,然后把这个hashCode作为下标,把对象作为元素值保存到数组中.这个时候这个数组就可以看做关联数组.java中没有关联数组这个概念,单独取了个名HashSet
        hash的目的就是为了查询快:hash值是一个固定位数值,整型值.所以在定长数据的情况下,查询是极快的,用数组也行,但是数组只能保存同一数据类型,HashSet能保存任意数据类型
        Hash的过程:
            拿到对象,调用他自己的hash算法,生成一个唯一的hash值,然后把这个值保存到数组中,整个过程就是hash.数组,和唯一值,和对象的关系,我们就叫HashSet;
            hash算法在java中就是指Object中的hashCode()函数里面的算法,这一个是你根据你的类来自己定义的

    为什么无序,为什么不可重复?
        1 生成的hashCode没有一定大小关系,就无所谓顺序
        2 因为每个对象都必须生成一个唯一的hashCode,如果是重复的,肯定生成一个同一个hashCode.这个时候就没有办法唯一性查询出某个数据.所以不可重复

        HashSet 是HashMap的一个实现,本质是HashMap.是HashMap集合中key部分,所以所以他们都需要重写Object中的hashCode()和equals();
        为什么需要重写hashCode()和equals()?
        在Object类中,原生的hashCode()方法,是把内存地址作为原始数据进行hashCode()运行得到的hash值.但是在实际中我们不可能知道每个对象的内存地址,如果我们用了内存地址,hash后就成了一个没有任何意义的hash数组(hash表).没有任何意义.我们如果需要比较大小的话,就只能根据类中给每个对象指定那个唯一的特征码进行运算,如:数据库中的ID,或者任何一个特殊的编号.你可以用类的地址作为hash原始值.equals()也一样,是对两个对象的内存地址进行比较,而实际中相等判断肯定不是比较内存地址,所以也需要按照某个属性进行重写,这样才有意义
        SortedSet:
        SortedSet集合存储元素为什么可以自动排序?
            因为被存储的元素(对象)实现了Compareable借口;
            Oracle编写的TreeSet集合在添加元素的时候,会自动调用CompareTo方法完成比较.
        集合Tree类型底层是红黑树,在装入之前就排序,排序有三种(两个借口):
            1 java.lang.Compareable;里面compareTo()方法,需要把compareTo()加载重写在对象里面
                这种方法需要对象类去实现Comparable借口,重写方法
            2 让SortedSet集合做到排序还有另外一种方法:java.util.Comparator;比较器借口;写一个比较器在元素加载之前先进行比较
            3 写一个匿名比较类,但是本质还是java.util.Comparator比较器类

    Map:
        Map没有继承Collection接口,Map提供key到value的映射。一个Map中不能包含相同的key,每个key只能映射一个 value。Map接口提供3种集合的视图,Map的内容可以被当作一组key集合,一组value集合,或者一组key-value映射。
        Map集合和Collection不一样,但是操作基本一样,只是有一些细微的差别
        增:
          Object put(Object key, Object value);
          向集合中添加键值对,也就是映射关系对象
        删
           void clear();
           清空Map;
        改
           数据类型转换
        查
           int size(); //获取Map中键值对的个数
           boolean isEmpty();//判断是否为空
           Object get(Object key);//通过key获取对应对象的值
           Collection values();//获取map集合中所有value对象的集合
           boolean containsKey(Object key);//判断集合中是否有这样的key键
           boolean containsValue(Object value)//判断集合中是否有这样的值
           Set keySet();//获取集合中所有的key,以集合方式返回
           Set entrySet;//返回此映射中包含的映射关系,以Set集合方式返回
           V remove(Object key) 如果存在一个键的映射关系,则将其从此映射中移除(可选操作)
    怎么向Hash表中添加元素?
        1 要添加的时候,HaspMap保存的是映射关系,这个映射关系靠什么来维护(Map.Entry(K,V)),是一个借口,那我们就可以传入各种对象的映射关系.
        如果生成了重复的值,就会往HashTable同位上加一个单项链表
        单项链表中每个对象都是一个Entry.
        单向链表节点:有一个Entry(key,value)
                     final key
                     下一个链表节点的内存地址
        2 添加过程:先调用要存储的映射关系的key对象,然后调用key对象自身的hashCode(),生成hash码,向数组中添加元素如果没有这个hash码,就占用一个数组的空间,保存这个key-value映射对象Entry.如果数组中已经存在了这个hash码,就把数组中当前保存的那个节点向后移动一位,再把当前的这个映射关系对象Entry保存到数组中.equals()比较一次,比较是key对象生成的hash码
        equals(),把键的值挨个在链表中进行比较,如果返回true那么就代表该链表中已经有了这个key值,就放弃添加,如果没有则返回false,然后连值一起放到当前hash值得链表
    
      

下面这张图是向Hash表中添加元素的图解
    

posted @ 2015-07-25 23:51  King_J  阅读(603)  评论(0编辑  收藏  举报