最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java ArrayList 實(shí)現(xiàn)實(shí)例講解

 更新時(shí)間:2016年11月03日 09:03:25   作者:有女朋友的程序猿  
ArrayList是基于數(shù)組實(shí)現(xiàn)的,是一個(gè)動(dòng)態(tài)數(shù)組,其容量能自動(dòng)增長(zhǎng),類似于C語言中的動(dòng)態(tài)申請(qǐng)內(nèi)存,動(dòng)態(tài)增長(zhǎng)內(nèi)存。這篇文章主要介紹了java ArrayList 實(shí)現(xiàn)的相關(guān)資料,需要的朋友可以參考下

 ArrayList概述: 

ArrayList是基于數(shù)組實(shí)現(xiàn)的,是一個(gè)動(dòng)態(tài)數(shù)組,其容量能自動(dòng)增長(zhǎng),類似于C語言中的動(dòng)態(tài)申請(qǐng)內(nèi)存,動(dòng)態(tài)增長(zhǎng)內(nèi)存。

    ArrayList不是線程安全的,只能用在單線程環(huán)境下,多線程環(huán)境下可以考慮用Collections.synchronizedList(List l)函數(shù)返回一個(gè)線程安全的ArrayList類,也可以使用concurrent并發(fā)包下的CopyOnWriteArrayList類。

    ArrayList實(shí)現(xiàn)了Serializable接口,因此它支持序列化,能夠通過序列化傳輸,實(shí)現(xiàn)了RandomAccess接口,支持快速隨機(jī)訪問,實(shí)際上就是通過下標(biāo)序號(hào)進(jìn)行快速訪問,實(shí)現(xiàn)了Cloneable接口,能被克隆。

   每個(gè)ArrayList實(shí)例都有一個(gè)容量,該容量是指用來存儲(chǔ)列表元素的數(shù)組的大小。它總是至少等于列表的大小。隨著向ArrayList中不斷添加元素,其容量也自動(dòng)增長(zhǎng)。自動(dòng)增長(zhǎng)會(huì)帶來數(shù)據(jù)向新數(shù)組的重新拷貝,因此,如果可預(yù)知數(shù)據(jù)量的多少,可在構(gòu)造ArrayList時(shí)指定其容量。在添加大量元素前,應(yīng)用程序也可以使用ensureCapacity操作來增加ArrayList實(shí)例的容量,這可以減少遞增式再分配的數(shù)量。 

   注意,此實(shí)現(xiàn)不是同步的。如果多個(gè)線程同時(shí)訪問一個(gè)ArrayList實(shí)例,而其中至少一個(gè)線程從結(jié)構(gòu)上修改了列表,那么它必須保持外部同步。

下面對(duì)java arraylist做一個(gè)記錄和總結(jié)吧

public class arraylist<E> {
  /**
   * 存放集合的元素 
   * 
   */
  private transient Object[] elementData;
  /** 元素的大小 */
  private int size;

定義了一個(gè)泛型類,一個(gè)object的數(shù)組和一個(gè)私有變量來記錄該集合的元素?cái)?shù)量,原文多了一個(gè)私有變量,我也不知道干嘛用的,作者也沒解釋也沒提及到,我沒使用也沒事

/**
   * 根據(jù)指定大小初始化
   * @param initialCapacity
   */
  public arraylist(int initialCapacity){
    super();
    if(initialCapacity<=0){
      //拋異常
      throw new IllegalArgumentException("初始化參數(shù)不能小于0");
    }else{
      //初始化數(shù)組
      this.elementData=new Object[initialCapacity];
    }
  }
  /**
   * 默認(rèn)初始化
   */
  public arraylist(){
    this(10);
  }
  /**
   * 根據(jù)一個(gè)集合類初始化
   * @param c 一個(gè)必須繼承了Collection接口的類
   */
  public arraylist(Collection<? extends E> c){
    //初始化
    elementData=c.toArray();
    size=elementData.length;
    //如果不是任意類型的數(shù)組就轉(zhuǎn)換Objec類型
    if (elementData.getClass() != Object[].class){
      elementData=Arrays.copyOf(elementData,size, Object[].class);
    }
  }

3個(gè)初始化方法,根據(jù)默認(rèn)大小進(jìn)行數(shù)組的初始化,給定大小初始化和傳遞一個(gè)繼承了Collection集合接口的類進(jìn)行轉(zhuǎn)換賦值初始化

/**
   * 擴(kuò)容集合
   * @param minCapacity
   */
  public void ensureCapacity(int minCapacity){
    /** 當(dāng)前數(shù)組的大小 */
    int oldCapacity = elementData.length; 
    if (minCapacity > oldCapacity) {
      /**
       * oldData 雖然沒有被使用,但是這是關(guān)于內(nèi)存管理的原因和Arrays.copyOf()方法不是線程安全
       * oldData在if的生命周期內(nèi)引用elementData這個(gè)變量,所以不會(huì)被GC回收掉
       * 當(dāng)Arrays.copyOf()方法在把elementData復(fù)制到newCapacity時(shí),就可以防止新的內(nèi)存或是其他線程分配內(nèi)存是elementData內(nèi)存被侵占修改
       * 當(dāng)結(jié)束是離開if,oldData周期就結(jié)束被回收
       */
      Object oldData[] = elementData; 
      int newCapacity = (oldCapacity * 3)/2 + 1; //增加50%+1
        if (newCapacity < minCapacity) 
          newCapacity = minCapacity; 
     //使用Arrays.copyOf把集合的元素復(fù)制并生成一個(gè)新的數(shù)組
     elementData = Arrays.copyOf(elementData, newCapacity); 
    } 
  }

這是一個(gè)核心的方法,集合的擴(kuò)容,其實(shí)是對(duì)數(shù)組的擴(kuò)容,minCapacity集合的大小,進(jìn)行對(duì)比判斷是否應(yīng)該進(jìn)行擴(kuò)容,使用了Arrays.copyOf()方法進(jìn)行擴(kuò)容,

原文有進(jìn)行詳細(xì)的解釋,這個(gè)方法把第一個(gè)參數(shù)的內(nèi)容復(fù)制到一個(gè)新的數(shù)組中,數(shù)組的大小是第二個(gè)參數(shù),并返回一個(gè)新的數(shù)組,關(guān)于oldData的變量上文有詳細(xì)的注釋

 /**
   * 檢查索引是否出界
   * @param index
   */
  private void RangeCheck(int index){
    if(index > size || index < 0){
      throw new IndexOutOfBoundsException("下標(biāo)超出,Index: " + index + ", Size: " +size);
    }
  }

一個(gè)下標(biāo)的檢索是否出 1 /**

* 添加元素
   * 將指定的元素添加到集合的末尾
   * @param e 添加的元素
   * @return
   */
  public boolean add(E e){
    ensureCapacity(size+1);
    elementData[size]=e;
    size++;
    return true;
  }

添加元素,先進(jìn)行擴(kuò)容,在賦值,然后元素加一,注意 size+1 字段size并沒有加一,這里進(jìn)行的是算術(shù)的運(yùn)算,所以在后面才需要進(jìn)行自增

/**
   * 添加元素
   * 將元素添加到指定的位置
   * @param index 指定的索引下標(biāo)
   * @param element 元素
   * @return
   */
  public boolean add(int index, E element){
    RangeCheck(index);
    ensureCapacity(size+1);
    // 將 elementData中從Index位置開始、長(zhǎng)度為size-index的元素, 
    // 拷貝到從下標(biāo)為index+1位置開始的新的elementData數(shù)組中。 
    // 即將當(dāng)前位于該位置的元素以及所有后續(xù)元素右移一個(gè)位置。
    System.arraycopy(elementData, index, elementData, index+1, size-index);
    elementData[index]=element;
    size++;//元素加一
    return true;
  }

這里不同的是 System.arraycopy(elementData, index, elementData, index+1, size-index);

這是一個(gè)c的內(nèi)部方法,詳細(xì)的原文有解釋,這里就不說了,這個(gè)也是整個(gè)ArrayList的核心所在,也Arrays.copyOf()的內(nèi)部實(shí)現(xiàn)原理

/**
   * 添加全部元素
   * 按照指定collection的迭代器所返回的元素順序,將該collection中的所有元素添加到此列表的尾部。 
   * @param c
   * @return
   */
  public boolean addAll(Collection < ? extends E>c){
    Object[] newElement=c.toArray();
    int elementLength=newElement.length;
    ensureCapacity(size+elementLength);
    //從newElement 0的下標(biāo)開始,elementLength個(gè)元素,elementData size的下標(biāo) 
    System.arraycopy(newElement, 0, elementData, size, elementLength);
    size+=elementLength;
    return elementLength!=0;
  }

基本上其他方法都只是根據(jù)不同的情況進(jìn)行不同的處理,比如通過接口把數(shù)據(jù)對(duì)象傳遞進(jìn)來然后獲取長(zhǎng)度進(jìn)行擴(kuò)容,在把數(shù)據(jù)使用System,arraycopy復(fù)制到新的數(shù)組中

/**
   * 指定位置,添加全部元素
   * @param index 插入位置的下標(biāo)
   * @param c 插入的元素集合
   * @return
   */
  public boolean addAll(int index, Collection<? extends E> c){
    if(index > size || index < 0){
      throw new IndexOutOfBoundsException("Index: " + index + ", Size: " +size);
    }
    Object[] newElement=c.toArray();
    int elementLength=newElement.length;
    ensureCapacity(size+elementLength);
    int numMoved=size-index;
    //判斷插入的位置是否在數(shù)組中間
    if(numMoved>0){
      //把index插入位置的后面的所有元素往后移
      //elementData index下標(biāo)開始的numMoved個(gè)元素插入到elementData 的index+elementLength位置
      System.arraycopy(elementData, index, elementData, index+elementLength, numMoved);
    }
    //把newElement里從0開始的elementLength個(gè)元素添加到elementData index開始的位置
    System.arraycopy(newElement, 0, elementData, index, elementLength); 
    size += elementLength; 
    return elementLength != 0;
  }
  
  /**
   * 指定下標(biāo)賦值
   * @param index
   * @param element
   * @return
   */
  public E set(int index,E element){
    RangeCheck(index);
    E oldElement=(E)elementData[index];
    elementData[index]=element;
    return oldElement;
  }
  
  /**
   * 根據(jù)下標(biāo)取值
   * @param index
   * @return
   */
  public E get(int index){
    RangeCheck(index);
    return (E)elementData[index];
  }
  
  /**
   * 根據(jù)下標(biāo)移除元素
   * @param index 
   */
  public E remove(int index){
    RangeCheck(index);
    E oldElement=(E)elementData[index];
    /** 移除的下標(biāo)后面的元素?cái)?shù)量 */
    int numMoved=size-index-1;
    //如果在數(shù)組范圍內(nèi)就進(jìn)行移動(dòng)
    if(numMoved>0)
      System.arraycopy(elementData, index+1, elementData, index, numMoved);
    //移除
    elementData[--size]=null;
    return oldElement;
  }
  
  /**
   * 根據(jù)元素移除
   * @param obj
   * @return
   */
  public boolean remove(Object obj){
    //Arraylist允許存放null,所以也要進(jìn)行判斷處理
    if(obj==null){
      for(int index=0;index<size;index++){
        if(elementData[index]==null){
           remove(index);
           return true;
        }
      }
    }else{
      for(int index=0;index<size;index++){
        if(obj.equals(elementData[index])){
           remove(index);
           return true;
        }
      }
    }
    return false;
  }
  
  /**
   * 根據(jù)下標(biāo)移除指定范圍內(nèi)的元素
   * @param fromIndex 開始
   * @param toIndex 結(jié)束
   */
  protected void removeRange(int fromIndex, int toIndex){
    RangeCheck(fromIndex);
    RangeCheck(toIndex);
    //要移動(dòng)的元素?cái)?shù)
    int numMoved = size - toIndex; 
    //把toIndex后面的元素移動(dòng)到fromIndex
    System.arraycopy(elementData, toIndex, elementData, fromIndex, numMoved);
    //要移除的元素?cái)?shù)量
    int newSize=size-(toIndex-fromIndex);
    while(size!=newSize){
      elementData[--size]=null;
    } 
  }
  
  /**
   * 把數(shù)組容量調(diào)整到實(shí)際的容量
   */
  public void trimToSize(){
    int leng=elementData.length;
    if(size<leng){
      Object[] old=elementData;
      elementData=Arrays.copyOf(elementData, size);
    }
  }
  /**
   * 把集合元素轉(zhuǎn)換成數(shù)組
   * @return
   */
  public Object[] toArray(){
    return Arrays.copyOf(elementData, size);
  }
  
  public <T>T[] toArray(T[] a){
    if(a.length<size){
      return (T[]) Arrays.copyOf(elementData,size, a.getClass());
    }
    //把集合元素復(fù)制到a數(shù)組中
    System.arraycopy(elementData, 0, a, 0, size);
     if (a.length > size){
       for(int index=size;index<a.length;index++){
         a[index] = null;
       }
     }
     return a; 
  }

基本上都是對(duì)數(shù)組進(jìn)行操作和使用c的方法進(jìn)行賦值移動(dòng)等,詳細(xì)的可以查看原文,原文中除了那個(gè)私有變量外也沒多少問題,代碼可以完美運(yùn)行,這李要注意的和難點(diǎn)就會(huì)是System,arraycopy和Arrayist.copy()這2個(gè)方法
和在擴(kuò)容方法里oldData這個(gè)變量的使用,這個(gè)變量真的很好,一開始我也不知道為什么要這么使用,在原文的末尾會(huì)進(jìn)行解釋。

以上所述是小編給大家介紹的Java ArrayList 實(shí)現(xiàn)實(shí)例講解,希望對(duì)大家有所幫助,如果大家有任何疑問歡迎給我留言,小編會(huì)及時(shí)回復(fù)大家的,在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!

相關(guān)文章

  • Java生成pdf文件或jpg圖片的案例講解

    Java生成pdf文件或jpg圖片的案例講解

    這篇文章主要介紹了Java生成pdf文件或jpg圖片的案例講解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2021-01-01
  • 一文詳解如何使用Java分割PDF文件

    一文詳解如何使用Java分割PDF文件

    PDF是一種用于顯示和打印文檔的文件格式,它非常廣泛地應(yīng)用于電子書籍、報(bào)告、合同等文件的傳遞和共享,這篇文章主要給大家介紹了關(guān)于如何使用Java分割PDF文件的相關(guān)資料,需要的朋友可以參考下
    2024-01-01
  • 十種JAVA排序算法實(shí)例

    十種JAVA排序算法實(shí)例

    本文件講了十種JAVA排序方法(冒泡(Bubble)排序——相鄰交換 、選擇排序——每次最小/大排在相應(yīng)的位置 、插入排序——將下一個(gè)插入已排好的序列中 、殼(Shell)排序——縮小增量 、歸并排序 、快速排序 、堆排序 、拓?fù)渑判?、錦標(biāo)賽排序 、基數(shù)排序)的使用,并提供了實(shí)例代碼可參考
    2013-11-11
  • Java中Steam流的用法詳解

    Java中Steam流的用法詳解

    Stream是Java?8?API添加的一個(gè)新的抽象,稱為流Stream,本文主要介紹了Java中Steam流的用法詳解,具有一定的參考價(jià)值,感興趣的可以了解一下
    2023-04-04
  • springboot實(shí)現(xiàn)將自定義日志格式存儲(chǔ)到mongodb中

    springboot實(shí)現(xiàn)將自定義日志格式存儲(chǔ)到mongodb中

    這篇文章主要介紹了springboot實(shí)現(xiàn)將自定義日志格式存儲(chǔ)到mongodb中的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • java并發(fā)編程JUC CountDownLatch線程同步

    java并發(fā)編程JUC CountDownLatch線程同步

    這篇文章主要介紹CountDownLatch是什么、CountDownLatch 如何工作、CountDownLatch 的代碼例子來展開對(duì)java并發(fā)編程JUC CountDownLatch線程同步,需要的朋友可以參考下面文章內(nèi)容
    2021-09-09
  • Java兩種方法計(jì)算出階乘尾部連續(xù)0的個(gè)數(shù)

    Java兩種方法計(jì)算出階乘尾部連續(xù)0的個(gè)數(shù)

    這篇文章主要介紹了Java兩種方法計(jì)算出階乘尾部連續(xù)0的個(gè)數(shù),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-03-03
  • Spring中的ConversionService源碼解析

    Spring中的ConversionService源碼解析

    這篇文章主要介紹了Spring中的ConversionService源碼解析,ConversionService是類型轉(zhuǎn)換服務(wù)的接口,從名字就可以看出ConverterRegistry是要實(shí)現(xiàn)轉(zhuǎn)換器注冊(cè)表的接口,添加和移除Converter和GenericConverter,需要的朋友可以參考下
    2023-11-11
  • 在springboot中使用攔截器的步驟詳解

    在springboot中使用攔截器的步驟詳解

    攔截器Interceptor,是SpringMVC中的核心內(nèi)容,在SpringBoot中使用Interceptor,同時(shí)采用全注解開發(fā),這篇文章主要介紹了在springboot中使用攔截器的步驟,需要的朋友可以參考下
    2022-01-01
  • Java日常練習(xí)題,每天進(jìn)步一點(diǎn)點(diǎn)(62)

    Java日常練習(xí)題,每天進(jìn)步一點(diǎn)點(diǎn)(62)

    下面小編就為大家?guī)硪黄狫ava基礎(chǔ)的幾道練習(xí)題(分享)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧,希望可以幫到你
    2021-08-08

最新評(píng)論

贡嘎县| 泊头市| 星座| 克什克腾旗| 汝城县| 申扎县| 习水县| 西平县| 竹北市| 科技| 新乡市| 芷江| 资溪县| 舒兰市| 迁西县| 宾阳县| 东辽县| 通榆县| 台湾省| 靖远县| 扶沟县| 嘉鱼县| 金昌市| 普安县| 兴海县| 深州市| 张家口市| 富宁县| 喀喇沁旗| 肇东市| 邹平县| 旬阳县| 泾阳县| 青浦区| 穆棱市| 策勒县| 阜阳市| 丰镇市| 荣昌县| 苏尼特左旗| SHOW|