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

如何實(shí)現(xiàn)Java的ArrayList經(jīng)典實(shí)體類

 更新時(shí)間:2017年02月08日 14:37:26   作者:byhieg  
ArrayList是Java集合框架中一個(gè)經(jīng)典的實(shí)現(xiàn)類。他比起常用的數(shù)組而言,明顯的優(yōu)點(diǎn)在于,可以隨意的添加和刪除元素而不需考慮數(shù)組的大小。下面跟著小編一起來看下吧

ArrayList是Java集合框架中一個(gè)經(jīng)典的實(shí)現(xiàn)類。他比起常用的數(shù)組而言,明顯的優(yōu)點(diǎn)在于,可以隨意的添加和刪除元素而不需考慮數(shù)組的大小。處于練手的目的,實(shí)現(xiàn)一個(gè)簡(jiǎn)單的ArrayList,并且把實(shí)現(xiàn)的過程在此記錄。

實(shí)現(xiàn)的ArrayList主要的功能如下:

  • 默認(rèn)構(gòu)造器和一個(gè)參數(shù)的有參構(gòu)造器
  • add方法
  • get方法
  • indexOf方法
  • contains方法
  • size方法
  • isEmpty方法
  • remove方法
  • sort方法

這個(gè)簡(jiǎn)單的ArrayList類 取名為SimpleArrayList,全部的代碼查看SimpleArrayList代碼

構(gòu)造器

源碼ArrayList一共有三個(gè)構(gòu)造器,一個(gè)無參構(gòu)造器,一個(gè)參數(shù)為int型有參構(gòu)造器,一個(gè)參數(shù)為Collection型的有參構(gòu)造器。參數(shù)為Collection型的構(gòu)造器用來實(shí)現(xiàn)將其他繼承Collection類的容器類轉(zhuǎn)換成ArrayList。SimpleArrayList類因?yàn)檫€沒有手動(dòng)實(shí)現(xiàn)其他的容器類,所以實(shí)現(xiàn)的構(gòu)造方法只有2個(gè)。代碼如下:

 public SimpleArrayList(){
  this(DEFAULT_CAPACITY);
 }
 public SimpleArrayList(int size){
  if (size < 0){
   throw new IllegalArgumentException("默認(rèn)的大小" + size);
  }else{
   elementData = new Object[size];
  }
 }

無參構(gòu)造器中的 DEFAULT_CAPACITY是定義的私有變量,默認(rèn)值是10,用來創(chuàng)建一個(gè)大小為10的數(shù)組。有參構(gòu)造器中,int參數(shù)是用來生成一個(gè)指定大小的Object數(shù)組。將創(chuàng)建好的數(shù)組傳給elementData。elementData是真正的用來存儲(chǔ)元素的數(shù)組。

add方法

add 方法用來往容器中添加元素,add方法有兩個(gè)重載方法,一個(gè)是add(E e),另一個(gè)是add(int index, E e)。add本身很簡(jiǎn)單,但是要處理動(dòng)態(tài)數(shù)組,即數(shù)組大小不滿足的時(shí)候,擴(kuò)大數(shù)組的內(nèi)存。具體的代碼如下:

 public void add(E e){
  isCapacityEnough(size + 1);
  elementData[size++] = e;
 }

方法isCapacityEnough就是來判斷是否需要擴(kuò)容,傳入的參數(shù)就是最小的擴(kuò)容空間。因?yàn)閍dd一個(gè)元素,所以最小的擴(kuò)容空間,即新的長(zhǎng)度是所有元素+ 1。這里的size就是真正的元素個(gè)數(shù)。

 private void isCapacityEnough(int size){
  if (size > DEFAULT_CAPACITY){
   explicitCapacity(size);
  }
  if (size < 0){
   throw new OutOfMemoryError();
  }
 }

判斷擴(kuò)容的方法也很簡(jiǎn)單,判斷需要擴(kuò)容的空間是不是比默認(rèn)的空間大。如果需要的空間比默認(rèn)的空間大,就調(diào)用explicitCapacity進(jìn)行擴(kuò)容。這里有個(gè)size小于0的判斷,出現(xiàn)size小于0主要是因?yàn)楫?dāng)size超過Integer.MAX_VALUE就會(huì)變成負(fù)數(shù)。

 private final static int MAX_ARRAY_LENGTH = Integer.MAX_VALUE - 8;
 private void explicitCapacity(int capacity){
  int newLength = elementData.length * 2;
  if (newLength - capacity < 0){
   newLength = capacity;
  }
  if (newLength > (MAX_ARRAY_LENGTH)){
   newLength = (capacity > MAX_ARRAY_LENGTH ? Integer.MAX_VALUE : MAX_ARRAY_LENGTH);
  }
  elementData = Arrays.copyOf(elementData, newLength);
 }

上面的代碼是擴(kuò)容的代碼,首先,定義一個(gè)數(shù)組最大的容量的常量為最大值,這個(gè)值按照官方的源碼中的解釋是要有些VM保留了數(shù)組的頭部信息在數(shù)組中,因此實(shí)際存放數(shù)據(jù)的大小就是整數(shù)的最大值 - 8

然后設(shè)定一個(gè)要擴(kuò)容的數(shù)組的大小,雖然上面說了有一個(gè)擴(kuò)容空間的值 size + 1 ,這個(gè)是實(shí)際我們最小需要擴(kuò)容的大小。但為了繼續(xù)增加元素,而不頻繁的擴(kuò)容,因此一次性的申請(qǐng)多一些的擴(kuò)容空間。這里newLength 打算申請(qǐng)為 數(shù)組長(zhǎng)度的2倍,然后去判斷這個(gè)長(zhǎng)度是否滿足需要的擴(kuò)容空間的值。 即有了后續(xù)的兩段代碼

  if (newLength - capacity < 0){
   newLength = capacity;
  }
  if (newLength > (MAX_ARRAY_LENGTH)){
   newLength = (capacity > MAX_ARRAY_LENGTH ? Integer.MAX_VALUE : MAX_ARRAY_LENGTH);
  }

如果2倍的長(zhǎng)度仍然不滿足,則申請(qǐng)到需要的擴(kuò)容長(zhǎng)度。在我們只增加一個(gè)元素的情況下,這個(gè)判斷是永遠(yuǎn)不會(huì)生效的,但是如果有addAll方法,則增加的元素很多,就要導(dǎo)致一次申請(qǐng)2倍的長(zhǎng)度是不夠的。第二個(gè)判斷是判斷newLength的長(zhǎng)度如果超過上面定義的數(shù)組最大長(zhǎng)度則判斷要需要的擴(kuò)容空間是否大于數(shù)組最大長(zhǎng)度,如果大于則newLength為 MAX_VALUE ,否則為 MAX_ARRAY_LENGTH。

最后,真正實(shí)現(xiàn)數(shù)組擴(kuò)容到設(shè)定長(zhǎng)度的方法就沒意思了,調(diào)用Arrays.copyOf(elementData, newLength)得到一個(gè)擴(kuò)容后的數(shù)組。

add的另一個(gè)重載方法也很簡(jiǎn)單。

 public void add(int index, E e) {
  //判斷是不是越界
  checkRangeForAdd(index);
  //判斷需不需要擴(kuò)容
  isCapacityEnough(size + 1);
  //將index的元素及以后的元素向后移一位
  System.arraycopy(elementData,index,elementData,index + 1,size - index);
  //將index下標(biāo)的值設(shè)為e
  elementData[index] = e;
  size++;
 }
 private void checkRangeForAdd(int index){
  //這里index = size是被允許的,即支持頭,中間,尾部插入
  if (index < 0 || index > size){
   throw new IndexOutOfBoundsException("指定的index超過界限");
  }
 }

至此,一個(gè)簡(jiǎn)單的add方法就實(shí)現(xiàn)完了。

get方法

get方法用來得到容器中指定下標(biāo)的元素。方法實(shí)現(xiàn)比較簡(jiǎn)單,直接返回?cái)?shù)組中指定下標(biāo)的元素即可。

 private void checkRange(int index) {
  if (index >= size || index < 0){
   throw new IndexOutOfBoundsException("指定的index超過界限");
  }
 }
 public E get(int index){
  checkRange(index);
  return (E)elementData[index];
 }

indexOf方法

indexOf方法用來得到指定元素的下標(biāo)。實(shí)現(xiàn)起來比較簡(jiǎn)單,需要判斷傳入的元素,代碼如下:

 public int indexOf(Object o){
  if (o != null) {
   for (int i = 0 ; i < size ; i++){
    if (elementData[i].equals(0)){
     return i;
    }
   }
  }else {
   for (int i = 0 ; i < size ; i++){
    if (elementData[i] == null) {
     return i;
    }
   }
  }
  return -1;
 }

判斷傳入的元素是否為null,如果為null,則依次與null。如果不為空,則用equals依次比較。匹配成功就返回下標(biāo),匹配失敗就返回-1。

contains方法

contains用來判斷該容器中是否包含指定的元素。在有了indexOf方法的基礎(chǔ)上,contains的實(shí)現(xiàn)就很簡(jiǎn)單了。

  public boolean contains(Object o){
  return indexOf(o) >= 0;
  }

size方法

size方法用來得到容器類的元素個(gè)數(shù),實(shí)現(xiàn)很簡(jiǎn)單,直接返回size的大小即可。

 public int size(){
  return size;
 }

isEmpty方法

isEmpty方法用來判斷容器是否為空,判斷size方法的返回值是否為0即可。

 public boolean isEmpty(){
  return size() == 0;
 }

remove方法

remove方法是用來對(duì)容器類的元素進(jìn)行刪除,與add一樣,remove方法也有兩個(gè)重載方法,分別是

remove(Object o)和remove(int index)

  public E remove(int index) {
  E value = get(index);
  int moveSize = size - index - 1;
  if (moveSize > 0){
   System.arraycopy(elementData,index + 1, elementData,index,size - index - 1);
  }
  elementData[--size] = null;
  return value;
 }
 
 public boolean remove(Object o){
  if (contains(o)){
   remove(indexOf(o));
   return true;
  }else {
   return false;
  }
 }

第一個(gè)remove方法是核心方法,首先得到要?jiǎng)h除的下標(biāo)元素的值,然后判斷index后面的要前移的元素的個(gè)數(shù),如果個(gè)數(shù)大于零,則調(diào)用庫(kù)方法,將index后面的元素向前移一位。最后elementData[--size] = null;縮減size大小,并將原最后一位置空。

第二個(gè)remove方法不需要向第一個(gè)方法一樣,需要告訴使用者要?jiǎng)h除的下標(biāo)對(duì)應(yīng)的元素,只需要判斷是否刪除成功即可。如果要?jiǎng)h除的元素在列表中,則刪除成功,如果不在則失敗。因此調(diào)用contains方法就可以判斷是否要?jiǎng)h除的元素在列表中。在則調(diào)用remove(int index),不在則返回失敗。

總結(jié)

自此,一個(gè)簡(jiǎn)單的ArrayList就實(shí)現(xiàn)完了,實(shí)現(xiàn)的目的是為了弄清ArrayList動(dòng)態(tài)數(shù)組的原理以及add與remove方法的內(nèi)容實(shí)現(xiàn)。同時(shí),也清楚了ArrayList最大的擴(kuò)容空間就是Integer的最大值。該類的所有代碼在SimpleArrayList代碼

以上就是本文的全部?jī)?nèi)容,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來一定的幫助,同時(shí)也希望多多支持腳本之家!

相關(guān)文章

  • Java 關(guān)于時(shí)間復(fù)雜度和空間復(fù)雜度的深度刨析

    Java 關(guān)于時(shí)間復(fù)雜度和空間復(fù)雜度的深度刨析

    算法復(fù)雜度分為時(shí)間復(fù)雜度和空間復(fù)雜度。其作用: 時(shí)間復(fù)雜度是度量算法執(zhí)行的時(shí)間長(zhǎng)短;而空間復(fù)雜度是度量算法所需存儲(chǔ)空間的大小
    2021-11-11
  • Java序列化常見的三個(gè)問題

    Java序列化常見的三個(gè)問題

    這篇文章主要介紹了Java序列化常見的三個(gè)問題,幫助大家更好的理解和學(xué)習(xí)JAVA,感興趣的朋友可以了解下
    2020-08-08
  • Java算法之BFS,DFS,動(dòng)態(tài)規(guī)劃和貪心算法的實(shí)現(xiàn)

    Java算法之BFS,DFS,動(dòng)態(tài)規(guī)劃和貪心算法的實(shí)現(xiàn)

    廣度優(yōu)先搜索(BFS)和深度優(yōu)先搜索(DFS)是圖遍歷算法中最常見的兩種算法,主要用于解決搜索和遍歷問題。動(dòng)態(tài)規(guī)劃和貪心算法則用來解決優(yōu)化問題。本文就來看看這些算法的具體實(shí)現(xiàn)吧
    2023-04-04
  • Mybatis Log控制臺(tái)如何輸出打印SQL語句

    Mybatis Log控制臺(tái)如何輸出打印SQL語句

    這篇文章主要介紹了Mybatis Log控制臺(tái)如何輸出打印SQL語句,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-07-07
  • 解決使用@ResponseBody后返回500錯(cuò)誤的問題

    解決使用@ResponseBody后返回500錯(cuò)誤的問題

    這篇文章主要介紹了解決使用@ResponseBody后返回500錯(cuò)誤的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-09-09
  • 基于SpringBoot和Dify實(shí)現(xiàn)流式響應(yīng)輸出

    基于SpringBoot和Dify實(shí)現(xiàn)流式響應(yīng)輸出

    這篇文章主要為大家詳細(xì)介紹了如何基于SpringBoot和Dify實(shí)現(xiàn)流式響應(yīng)輸出效果,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以參考一下
    2025-03-03
  • 詳解ArrayBlockQueue源碼解析

    詳解ArrayBlockQueue源碼解析

    這篇文章主要介紹了ArrayBlockQueue源碼解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04
  • Java注解詳解及實(shí)現(xiàn)自定義注解的方法

    Java注解詳解及實(shí)現(xiàn)自定義注解的方法

    這篇文章主要介紹了Java注解詳解及實(shí)現(xiàn)自定義注解的方法,本文給大家介紹了jdk中預(yù)定義的一些注解及自定義注解的相關(guān)知識(shí),需要的朋友可以參考下
    2022-06-06
  • 簡(jiǎn)介Java編程中的Object類

    簡(jiǎn)介Java編程中的Object類

    這篇文章主要介紹了簡(jiǎn)介Java編程中的Object類,是Java入門學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下
    2015-09-09
  • SpringBoot整合Redis時(shí)遇到連接問題的解決方法

    SpringBoot整合Redis時(shí)遇到連接問題的解決方法

    在使用Spring Boot整合Redis的過程中,經(jīng)常會(huì)遇到連接問題,尤其是當(dāng)Redis服務(wù)部署在遠(yuǎn)程服務(wù)器上時(shí),所以本文給大家介紹了SpringBoot整合Redis遇到連接問題的解決方法,需要的朋友可以參考下
    2024-11-11

最新評(píng)論

博爱县| 门头沟区| 日土县| 介休市| 彰化县| 洛扎县| 永泰县| 灵石县| 永年县| 华容县| 定日县| 遵化市| 商河县| 大邑县| 保亭| 沛县| 新郑市| 古丈县| 松潘县| 隆昌县| 宁乡县| 崇阳县| 金沙县| 梁河县| 四川省| 随州市| 增城市| 界首市| 宁晋县| 元阳县| 定南县| 交城县| 延庆县| 邵东县| 阳泉市| 临桂县| 元江| 赤水市| 浦城县| 柳江县| 宣化县|