zoukankan      html  css  js  c++  java
  • Java集合类的底层实现探索

    List:

      ArrayList

        首先我们来看看jdk的ArrayList的add方法的源码是如何实现的:     

        public boolean add(E e) {
          ensureCapacityInternal(size + 1); // Increments modCount!!
          elementData[size++] = e;
          return true;
        }

        在AarryList类有如下数组的定义

                  /**
        * The array buffer into which the elements of the ArrayList are stored. --这是个存储ArrayList元素的数组
        * The capacity of the ArrayList is the length of this array buffer.  ---ArrayList的长度即是数组的长度
        */
        private transient Object[] elementData;

                综上所看,ArrayList底层存储的实现是通过一个数组来实现的

          

           LinkedList

      上源码:

      /**
      * Pointer to first node.
      * Invariant: (first == null && last == null) ||
      * (first.prev == null && first.item != null)
      */
      transient Node<E> first;

      /**
      * Pointer to last node.
      * Invariant: (first == null && last == null) ||
      * (last.next == null && last.item != null)
      */
      transient Node<E> last;

      /**
      * Links e as last element.
      */
      void linkLast(E e) {
        final Node<E> l = last;
        final Node<E> newNode = new Node<>(l, e, null);
        last = newNode;
        if (l == null)
          first = newNode;
        else
          l.next = newNode;
        size++;
        modCount++;
       }

              //在ArrayList内部是有这么一个作为"节点"的内部类的

              private static class Node<E> {
        E item;
        Node<E> next;
        Node<E> prev;

        Node(Node<E> prev, E element, Node<E> next) {
          this.item = element;
          this.next = next;
          this.prev = prev;
        }
      }

           个人理解:至此可以猜测到LinkedList底层实现是链表;这里代码只是列举了往集合末尾添加元素的情况,具体看linkLast(E e)这个方法

                          linkLast方法内会根据参数e生成Node,再根据tail具体情况,修改生成node的pre/next指向,存储形式也就是链表啦

          Map:

          map的底层实现是  数组+链表

               描述一下map存储key-value的过程:

                 key和value两个对象put到map的时候,会被封装成Entry<K,V>实体对象;put过程会根据K值生成一个hash码值(int类型,不同的key可能会生成相同的hash码)

                       这个hash码会被当成数组的索引/下标(index),数组的每个下标对应一个hash码,而一个hash码对应一个链表(链表存储着具有相同hash码的对象)

                      比如: 现在要  map.put("aa","123");  "aa"对应的hash码是121

                                             map.put("bb","123"); "bb"对应的hash码也是121  执行put操作的时候程序会先到数组找到下标为121(也就是hash的数值)的链表,再通过链表存储put进来的对象

             具体代码:

        

        /**
        * Associates the specified value with the specified key in this map.
        * If the map previously contained a mapping for the key, the old
        * value is replaced.
        *
        * @param key key with which the specified value is to be associated
        * @param value value to be associated with the specified key
        * @return the previous value associated with <tt>key</tt>, or
        * <tt>null</tt> if there was no mapping for <tt>key</tt>.
        * (A <tt>null</tt> return can also indicate that the map
        * previously associated <tt>null</tt> with <tt>key</tt>.)
        */
        public V put(K key, V value) {
          if (key == null)
            return putForNullKey(value);
            int hash = hash(key.hashCode());
            int i = indexFor(hash, table.length);  //找出数组对应的下标
            for (Entry<K,V> e = table[i]; e != null; e = e.next) {  //找到数组内对应下标的链表对象
              Object k;
            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {  //原先key已经存在时,覆盖操作
              V oldValue = e.value;
              e.value = value;
              e.recordAccess(this);
              return oldValue;
            }
          }

          modCount++;
          addEntry(hash, key, value, i);//原先不存在key对应的Entry则在链表后添加
          return null;
         }

          Set

             set的特点是无序,不重复

        // Dummy value to associate with an Object in the backing Map
        private static final Object PRESENT = new Object();

        public boolean add(E e) {
          return map.put(e, PRESENT)==null;
        }

                 以上是HashSet源码,可以看出HashSet底层是通过Map来实现的,不重复实现:e的hash值相同时,Map会采取覆盖的形式,这样就不会有重复了

                Map的无序也就自然导致了HashSet的无序了(hash值求法?HashCode与equals)

         "打完收工"....

  • 相关阅读:
    大三小学期 Android开发的一些经验
    高德地图显示不出来
    imageview无法显示图片:java.lang.RuntimeException: Canvas: trying to draw too large(281520000bytes) bitmap
    设置ImageView显示的图片铺满全屏
    大三小学期 web前端开发的一些小经验
    HTML5----响应式(自适应)网页设计
    div闪一下就消失
    登录界面输入判断为空的bug
    Solr之.net操作
    Java Web之路(一)Servlet
  • 原文地址:https://www.cnblogs.com/fzczailushang/p/7383717.html
Copyright © 2011-2022 走看看